From 327d30ec91fc37a33524e7ea9a6f9e6bbbff3ba1 Mon Sep 17 00:00:00 2001 From: David Waring Date: Wed, 22 Feb 2023 11:46:06 +0000 Subject: [PATCH 01/48] Bump version for next major release on the development branch. --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index a189662..72eb1d2 100644 --- a/meson.build +++ b/meson.build @@ -6,8 +6,8 @@ # program. If this file is missing then the license can be retrieved from # https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view -project('rt-5gms-af', 'c', - version : '1.1.0', +project('rt-5gms-application-function', 'c', + version : '1.2.0', license : '5G-MAG Public', meson_version : '>= 0.47.0', default_options : [ From c013d1a217a8b8a1e6000e9148295cbab699312d Mon Sep 17 00:00:00 2001 From: "Jordi J. Gimenez" <87380947+jordijoangimenez@users.noreply.github.com> Date: Sun, 26 Feb 2023 19:42:32 +0100 Subject: [PATCH 02/48] Update README.md --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index baa8df9..1508093 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,7 @@ This AF uses the [Open5GS](https://open5gs.org/) framework to implement the netw ## Specifications -* [ETSI TS 126 501](https://portal.etsi.org/webapp/workprogram/Report_WorkItem.asp?WKI_ID=67203) - 5G Media Streaming ( - 5GMS): General description and architecture (3GPP TS 26.501 version 17.3.0 Release 17) -* [ETSI TS 126 512](https://portal.etsi.org/webapp/workprogram/Report_WorkItem.asp?WKI_ID=67679) - 5G Media Streaming ( - 5GMS): Protocols (3GPP TS 26.512 version 17.3.0 Release 17) +A list of specification related to this repository is available [here](https://github.com/5G-MAG/Standards/blob/main/Specifications_5GMS.md). ## Install dependencies From cd06178cd3169aee78c37eca522502bd5dd54c1f Mon Sep 17 00:00:00 2001 From: deva Date: Mon, 13 Feb 2023 09:08:47 +0000 Subject: [PATCH 03/48] Initial commit of the M1 interface --- examples/certmgr | 422 +++++++++ src/5gmsaf/application-server-context.c | 305 +++--- src/5gmsaf/application-server-context.h | 14 +- src/5gmsaf/certmgr.c | 270 ++++++ src/5gmsaf/certmgr.h | 43 + src/5gmsaf/context.c | 109 ++- src/5gmsaf/context.h | 13 + src/5gmsaf/event.h | 9 +- src/5gmsaf/hash.c | 30 + src/5gmsaf/hash.h | 29 + src/5gmsaf/init.c | 23 + src/5gmsaf/msaf-sm.c | 1125 +++++++++++++++-------- src/5gmsaf/provisioning-session.c | 55 +- src/5gmsaf/provisioning-session.h | 8 + src/5gmsaf/response-cache-control.c | 38 + src/5gmsaf/response-cache-control.h | 39 + src/5gmsaf/server.c | 263 ++++++ src/5gmsaf/server.h | 32 + src/5gmsaf/utilities.c | 41 + src/5gmsaf/utilities.h | 3 + 20 files changed, 2316 insertions(+), 555 deletions(-) create mode 100755 examples/certmgr create mode 100644 src/5gmsaf/certmgr.c create mode 100644 src/5gmsaf/certmgr.h create mode 100644 src/5gmsaf/hash.c create mode 100644 src/5gmsaf/hash.h create mode 100644 src/5gmsaf/response-cache-control.c create mode 100644 src/5gmsaf/response-cache-control.h create mode 100644 src/5gmsaf/server.c create mode 100644 src/5gmsaf/server.h diff --git a/examples/certmgr b/examples/certmgr new file mode 100755 index 0000000..ff6a75b --- /dev/null +++ b/examples/certmgr @@ -0,0 +1,422 @@ +#!/bin/bash +# +# 5G-MAG Reference Tools: Certificate Management script +# ====================================================== +# +# For full license terms please see the LICENSE file distributed with this +# program. If this file is missing then the license can be retrieved from +# https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +# +# This script will use wget and git to download the openapi-generator-cli tool +# and a specified branch of the 5G APIs. It will then create a set of bindings +# in a specified output language. +# + +# Save location of this script and the name it was called by +scriptname=`basename "$0"` +scriptdir=`dirname "$0"` +scriptdir=`cd "$scriptdir"; pwd` + +# Variables +default_cert_op= +cert_operation= +cert_store="/home/ubuntu/certificate" +common_name= +server_certificate_resource_id= +cert_status= +cert_subject= + +# Parse command line arguments +ARGS=`getopt -n "$scriptname" -o 'c:h' -l 'cert-operation:,help' -s sh -- "$@"` + +print_syntax() { + echo "Syntax: $scriptname [-h] -c " +} + +if [ $? -ne 0 ]; then + print_syntax >&2 + exit 1 +fi + +print_help() { + cat <&2 + print_syntax >&2 + exit 1 + ;; + esac +done + +if [ $# -gt 0 ]; then + echo "Error: Command line argument \"$1\" unexpected" >&2 + print_syntax >&2 + exit 1 +fi + +if [ -z "$CERTOPS" ]; then + echo 'Error: Required command line parameter are missing' >&2 + print_syntax >&2 + exit 1 +fi + +cert_store_create() { + if [ ! -d "$cert_store/csrs" ]; then + mkdir -p $cert_store/csrs + fi + if [ ! -d "$cert_store/private" ]; then + mkdir -p $cert_store/private + fi + + if [ ! -d "$cert_store/public" ]; then + mkdir -p $cert_store/public + fi + +} + +cert_store_check() { + if [ -f "$cert_store/csrs/$server_certificate_resource_id.pem" ]; then + echo "CSR for Server Certificate Resource $server_certificate_resource_id exists already" + cat "$cert_store/csrs/$server_certificate_resource_id.pem" + exit 3 + fi + + if [ -f "$cert_store/public/$server_certificate_resource_id.pem" ]; then + echo "Certificate for Server Certificate Resource $server_certificate_resource_id exists already" + cat "$cert_store/public/$server_certificate_resource_id.pem" + exit 3 + fi +} + +ca_cert_check() { + + if ! [[ ( -f "$cert_store/private/ca.key" ) && ( -f "$cert_store/public/ca.crt" ) ]]; then + + # CA self certificate + openssl req -new -nodes -x509 -days 90 -newkey rsa:2048 -keyout "$cert_store/private/ca.key" -out "$cert_store/public/ca.crt" -subj "/C=GB/L=London/CN=$common_name" -addext "subjectAltName=DNS:$common_name" > /dev/null 2>&1 + fi +} + +new_csr() { + + cert_store_check >&2 + + openssl req -new -newkey rsa:2048 -batch -nodes -keyout "$cert_store/private/$server_certificate_resource_id.pem" -out "$cert_store/csrs/$server_certificate_resource_id.pem" -subj "/C=GB/L=London/CN=$common_name" -addext "subjectAltName=DNS:$common_name" > /dev/null 2>&1 + cat "$cert_store/csrs/$server_certificate_resource_id.pem" + exit 0 + +} + +new_cert() { + + cert_store_check >&2 + ca_cert_check >&2 + + # Generate server cert to be signed + openssl req -new -newkey rsa:2048 -batch -nodes -keyout "$cert_store/private/$server_certificate_resource_id.pem" -out "$cert_store/csrs/$server_certificate_resource_id.pem" -subj "/C=GB/L=London/CN=$common_name" -addext "subjectAltName=DNS:$common_name" > /dev/null 2>&1 + + openssl x509 -req -CA "$cert_store/public/ca.crt" -CAkey "$cert_store/private/ca.key" -CAcreateserial -in "$cert_store/csrs/$server_certificate_resource_id.pem" -out "$cert_store/public/$server_certificate_resource_id.pem" -days 90 > /dev/null 2>&1 + + cat "$cert_store/public/$server_certificate_resource_id.pem" + exit 0 +} + +public_cert_get() { + + if ([ -f "$cert_store/csrs/$server_certificate_resource_id.pem" ] && ! [ -f "$cert_store/public/$server_certificate_resource_id.pem" ]); then + echo "Public Certificate for $server_certificate_resource_id not yet available." + exit 8 + fi + + if [ ! -f "$cert_store/public/$server_certificate_resource_id.pem" ]; then + echo "Certificate for $server_certificate_resource_id not found" + exit 4 + fi + + # cat $cert_store/public/$server_certificate_resource_id.pem $cert_store/public/ca.crt + + ts=`stat -c '%Y' /etc/hosts`; TZ=GMT date --date=@$ts +'%a, %d %b %Y %H:%M:%S %Z' > /dev/null 2>&1 + etag=`sha256sum "$cert_store/public/$server_certificate_resource_id.pem"` + + #printf '%s\t%s\t%s\n' \ + # "$ts" "$etag" `cat "$cert_store/public/$server_certificate_resource_id.pem"` + + + echo -e "$ts:$etag:`cat $cert_store/public/$server_certificate_resource_id.pem`" + + exit 0 +} + +server_cert_get() { + + if ( ! ( [ -f "$cert_store/public/$server_certificate_resource_id.pem" ] && [ -f "$cert_store/private/$server_certificate_resource_id.pem" ] )); then + echo "Credentials for $server_certificate_resource_id not yet available." + exit 8 + fi + + cat $cert_store/public/$server_certificate_resource_id.pem $cert_store/private/$server_certificate_resource_id.pem + exit 0 +} + +cert_set() { +< "$cert_store/public/$server_certificate_resource_id.pem" + exit 0 + + elif [ -f "$cert_store/public/$server_certificate_resource_id.pem" ]; then + echo "Certificate already exists for $server_certificate_resource_id." + exit 3 + + elif ! [ -f "$cert_store/csrs/$server_certificate_resource_id.pem" ]; then + echo "No CSR issued: $server_certificate_resource_id." + exit 4 + fi + +} + +cert_expiry_check() { + if (openssl x509 -checkend 86400 -noout -in "$cert_store/public/$server_certificate_resource_id.pem" > /dev/null 2>&1) ; then + cert_status= + else + cert_status="Expired or will expire within 24 hours" + fi +} + +cert_list() { + if ( [ -f "$cert_store/private/$server_certificate_resource_id.pem" ] && ! [ -f "$cert_store/public/$server_certificate_resource_id.pem" ] ); then + cert_status="Awaiting" + cert_subject= + printf '%s\t%s\n' \ + "$server_certificate_resource_id" "$cert_status" + elif [ -f "$cert_store/public/$server_certificate_resource_id.pem" ]; then + cert_expiry_check >&2 + cert_subject=`openssl x509 -noout -subject -in $cert_store/public/$server_certificate_resource_id.pem` + printf '%s\t%s\t%s\n' \ + "$server_certificate_resource_id" "$cert_subject" "$cert_status" + fi +} + + +check_cert_revoke() { + + issuer=`openssl x509 -in $cert_store/public/$server_certificate_resource_id.pem -inform PEM -noout -issuer` + subject=`openssl x509 -in $cert_store/public/$server_certificate_resource_id.pem -inform PEM -noout -subject` + issuer="${issuer//issuer=/ }" + subject="${subject//subject=/ }" + if [ "$issuer" = "$subject" ]; then + can_be_revoked=0 + echo "Cannot revoke as $server_certificate_resource_id.pem is a self-signed certificate" + else + can_be_revoked=1 + fi + +} + +cert_revoke() { + check_cert_revoke >&2 + echo "in cert_revoke: $can_be_revoked" + if [ "$can_be_revoked" -eq "0" ] ; then + + echo "in cert_revoke:exit 2 $can_be_revoked" + exit 2 + fi + + openssl ca -revoke $cert_store/public/$server_certificate_resource_id.pem -keyfile "$cert_store/private/ca.key" -cert "$cert_store/public/ca.crt" + exit 0 + +} + +cert_delete() { + if ( [ -f "$cert_store/private/$server_certificate_resource_id.pem" ]); then + rm -f "$cert_store/private/$server_certificate_resource_id.pem" + fi + if ( [ -f "$cert_store/public/$server_certificate_resource_id.pem" ]); then + rm -f "$cert_store/public/$server_certificate_resource_id.pem" + fi + if ( [ -f "$cert_store/csrs/$server_certificate_resource_id.pem" ]); then + rm -f "$cert_store/csrs/$server_certificate_resource_id.pem" + fi +} + +certificate_delete() { + + check_cert_revoke >&2 + if [ "$can_be_revoked" -eq "0" ] ; then + echo "certificate delete: $can_be_revoked" + cert_delete >&2 + else + cert_revoke >&2 + cert_delete >&2 + fi + exit 0 +} + +<&2 + if ! [ $can_be_revoked ]; then + exit 2 + fi + exit 0 + +} + +cert_delete() { + + cert_revoke >&2 + if ( [ -f "$cert_store/private/$server_certificate_resource_id.pem" ]); then + rm -f "$cert_store/private/$server_certificate_resource_id.pem" + fi + + +} +revdel + + +parse_opts() { + + read -r -a cert_operation <<< "$CERTOPS" + if [ "$cert_operation" == "newcsr" ]; then + if [ ${#cert_operation[@]} -lt 3 ]; then + echo "$cert_operation: Not enough information to create a new csr" + exit 1 + fi + server_certificate_resource_id=${cert_operation[1]} + common_name=${cert_operation[2]} + new_csr >&2 + exit 1 + fi + + if [ "$cert_operation" == "newcert" ]; then + if [ ${#cert_operation[@]} -lt 3 ]; then + echo "$cert_operation: Not enough information to create a new certificate" + exit 1 + fi + server_certificate_resource_id=${cert_operation[1]} + common_name=${cert_operation[2]} + new_cert >&2 + fi + + if [ "$cert_operation" == "publiccert" ]; then + if [ ${#cert_operation[@]} -eq 2 ]; then + server_certificate_resource_id=${cert_operation[1]} + public_cert_get >&2 + else + echo "$cert_operation: has invalid options" + exit 1 + fi + fi + + if [ "$cert_operation" == "servercert" ]; then + if [ ${#cert_operation[@]} -eq 2 ]; then + server_certificate_resource_id=${cert_operation[1]} + server_cert_get >&2 + else + echo "$cert_operation: has invalid options" + exit 1 + fi + fi + + if [ "$cert_operation" == "setcert" ]; then + if [ ${#cert_operation[@]} -eq 2 ]; then + server_certificate_resource_id=${cert_operation[1]} + cert_set >&2 + else + echo "$cert_operation: has invalid options" + exit 1 + fi + fi + + if [ "$cert_operation" == "revoke" ]; then + if [ ${#cert_operation[@]} -eq 2 ]; then + server_certificate_resource_id=${cert_operation[1]} + cert_revoke >&2 + else + echo "$cert_operation: has invalid options" + exit 1 + fi + + fi + + if [ "$cert_operation" == "delete" ]; then + if [ ${#cert_operation[@]} -eq 2 ]; then + server_certificate_resource_id=${cert_operation[1]} + certificate_delete >&2 + else + echo "$cert_operation: has invalid options" + exit 1 + fi + + fi + + if [ "$cert_operation" == "list" ]; then + if [ ${#cert_operation[@]} -eq 2 ]; then + server_certificate_resource_id=${cert_operation[1]} + cert_list >&2 + else + for pem in $cert_store/public/*.pem; do + server_certificate_resource_id=`basename "${pem%.*}"` + cert_list >&2 + done + fi + fi +} + +cert_store_create >&2 +parse_opts >&2 + +exit 0 diff --git a/src/5gmsaf/application-server-context.c b/src/5gmsaf/application-server-context.c index dabe052..1bbaccd 100644 --- a/src/5gmsaf/application-server-context.c +++ b/src/5gmsaf/application-server-context.c @@ -12,9 +12,17 @@ program. If this file is missing then the license can be retrieved from #include "context.h" #include "utilities.h" +typedef struct client_request_info { + msaf_application_server_state_node_t *as_state; + purge_resource_id_node_t *purge_node; + +} client_request_info_t; + + static void application_server_state_init(msaf_application_server_node_t *msaf_as); static ogs_sbi_client_t *msaf_m3_client_init(const char *hostname, int port); -static int m3_client_as_state_requests(msaf_application_server_state_node_t *as_state, const char *type, const char *data, const char *method, const char *component); +static int +m3_client_as_state_requests(msaf_application_server_state_node_t *as_state, purge_resource_id_node_t *purge_node,const char *type, const char *data, const char *method, const char *component); static int client_notify_cb(int status, ogs_sbi_response_t *response, void *data); static void msaf_application_server_remove(msaf_application_server_node_t *msaf_as); @@ -148,124 +156,112 @@ void next_action_for_application_server(msaf_application_server_state_node_t *as ogs_assert(as_state); if (as_state->current_certificates == NULL) { - ogs_debug("M3 client: Sending GET method to Application Server [%s] to request the list of known certificates", as_state->application_server->canonicalHostname); - m3_client_as_state_requests(as_state, NULL, NULL, (char *)OGS_SBI_HTTP_METHOD_GET, "certificates"); + m3_client_as_state_requests(as_state, NULL, NULL, NULL, (char *)OGS_SBI_HTTP_METHOD_GET, "certificates"); } else if (as_state->current_content_hosting_configurations == NULL) { - ogs_debug("M3 client: Sending GET method to Application Server [%s] to request the list of known content-hosting-configurations", as_state->application_server->canonicalHostname); - m3_client_as_state_requests(as_state, NULL, NULL, (char *)OGS_SBI_HTTP_METHOD_GET, "content-hosting-configurations"); + m3_client_as_state_requests(as_state, NULL, NULL, NULL, (char *)OGS_SBI_HTTP_METHOD_GET, "content-hosting-configurations"); } else if (ogs_list_first(&as_state->upload_certificates) != NULL) { - const char *upload_cert_filename; - char *upload_cert_id; - char *provisioning_session; - char *cert_id; - char *data; - char *component; - resource_id_node_t *cert_id_node; - - resource_id_node_t *upload_cert = ogs_list_first(&as_state->upload_certificates); - ogs_list_for_each(as_state->current_certificates, cert_id_node) { - if (!strcmp(cert_id_node->state, upload_cert->state)) { - break; - } - } - upload_cert_id = ogs_strdup(upload_cert->state); - provisioning_session = strtok_r(upload_cert_id,":",&cert_id); - upload_cert_filename = msaf_get_certificate_filename(provisioning_session, cert_id); - data = read_file(upload_cert_filename); - - if(!data) { - ogs_error("The certificate file [%s] referenced in the JSON cannot be read", upload_cert_filename); - } - - component = ogs_msprintf("certificates/%s:%s", provisioning_session, cert_id); - - if (cert_id_node) { - ogs_debug("M3 client: Sending PUT method to Application Server [%s] for Certificate: [%s]", as_state->application_server->canonicalHostname, upload_cert->state); - m3_client_as_state_requests(as_state, "application/x-pem-file", data, (char *)OGS_SBI_HTTP_METHOD_PUT, component); - free(data); - } else { - ogs_debug("M3 client: Sending POST method to Application Server [%s]for Certificate: [%s]", as_state->application_server->canonicalHostname, upload_cert->state); - m3_client_as_state_requests(as_state, "application/x-pem-file", data, (char *)OGS_SBI_HTTP_METHOD_POST, component); - free(data); + const char *upload_cert_filename; + char *upload_cert_id; + char *provisioning_session; + char *cert_id; + char *data; + char *component; + resource_id_node_t *cert_id_node; + + resource_id_node_t *upload_cert = ogs_list_first(&as_state->upload_certificates); + ogs_list_for_each(as_state->current_certificates, cert_id_node) { + if (!strcmp(cert_id_node->state, upload_cert->state)) { + break; } - ogs_free(component); - ogs_free(upload_cert_id); + } + upload_cert_id = ogs_strdup(upload_cert->state); + provisioning_session = strtok_r(upload_cert_id,":",&cert_id); + upload_cert_filename = msaf_get_certificate_filename(provisioning_session, cert_id); + data = read_file(upload_cert_filename); + component = ogs_msprintf("certificates/%s:%s", provisioning_session, cert_id); + + if (cert_id_node) { + ogs_debug("M3 client: Sending PUT method to Application Server [%s] for Certificate: [%s]", as_state->application_server->canonicalHostname, upload_cert->state); + m3_client_as_state_requests(as_state, NULL, "application/x-pem-file", data, (char *)OGS_SBI_HTTP_METHOD_PUT, component); + free(data); + } else { + ogs_debug("M3 client: Sending POST method to Application Server [%s]for Certificate: [%s]", as_state->application_server->canonicalHostname, upload_cert->state); + m3_client_as_state_requests(as_state, NULL, "application/x-pem-file", data, (char *)OGS_SBI_HTTP_METHOD_POST, component); + free(data); + } + ogs_free(component); + ogs_free(upload_cert_id); } else if (ogs_list_first(&as_state->upload_content_hosting_configurations) != NULL) { - msaf_provisioning_session_t *provisioning_session; - OpenAPI_content_hosting_configuration_t *chc_with_af_unique_cert_id; - char *data; - char *component; - resource_id_node_t *chc_id_node; - cJSON *json; - - resource_id_node_t *upload_chc = ogs_list_first(&as_state->upload_content_hosting_configurations); - ogs_list_for_each(as_state->current_content_hosting_configurations, chc_id_node) { - if (!strcmp(chc_id_node->state, upload_chc->state)) { - break; - } + msaf_provisioning_session_t *provisioning_session; + OpenAPI_content_hosting_configuration_t *chc_with_af_unique_cert_id; + char *data; + char *component; + resource_id_node_t *chc_id_node; + cJSON *json; + + resource_id_node_t *upload_chc = ogs_list_first(&as_state->upload_content_hosting_configurations); + ogs_list_for_each(as_state->current_content_hosting_configurations, chc_id_node) { + if (!strcmp(chc_id_node->state, upload_chc->state)) { + break; } + } - provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(upload_chc->state); - - chc_with_af_unique_cert_id = msaf_content_hosting_configuration_with_af_unique_cert_id(provisioning_session); + provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(upload_chc->state); - json = OpenAPI_content_hosting_configuration_convertToJSON(chc_with_af_unique_cert_id); + chc_with_af_unique_cert_id = msaf_content_hosting_configuration_with_af_unique_cert_id(provisioning_session); - if(!json) { - ogs_error("OpenAPI function is not able to convert The contentHostingConfiguration to JSON"); + json = OpenAPI_content_hosting_configuration_convertToJSON(chc_with_af_unique_cert_id); + data = cJSON_Print(json); - } + component = ogs_msprintf("content-hosting-configurations/%s", upload_chc->state); - data = cJSON_Print(json); - - if(!data) { - ogs_error("The contentHostingConfiguration cannot be parsed"); + if (chc_id_node) { + ogs_debug("M3 client: Sending PUT method to Application Server [%s] for Content Hosting Configuration: [%s]", as_state->application_server->canonicalHostname, upload_chc->state); + m3_client_as_state_requests(as_state, NULL, "application/json", data, (char *)OGS_SBI_HTTP_METHOD_PUT, component); + } else { + ogs_debug("M3 client: Sending POST method to Application Server [%s] for Content Hosting Configuration: [%s]", as_state->application_server->canonicalHostname, upload_chc->state); + m3_client_as_state_requests(as_state, NULL, "application/json", data, (char *)OGS_SBI_HTTP_METHOD_POST, component); + } + if (chc_with_af_unique_cert_id) OpenAPI_content_hosting_configuration_free(chc_with_af_unique_cert_id); + ogs_free(component); + cJSON_Delete(json); + } else if (ogs_list_first(&as_state->delete_content_hosting_configurations) != NULL) { + char *component; + resource_id_node_t *delete_chc = ogs_list_first(&as_state->delete_content_hosting_configurations); + ogs_debug("M3 client: Sending DELETE method for Content Hosting Configuration [%s] to the Application Server [%s]", delete_chc->state, as_state->application_server->canonicalHostname); + component = ogs_msprintf("content-hosting-configurations/%s", delete_chc->state); + m3_client_as_state_requests(as_state, NULL, NULL, NULL, (char *)OGS_SBI_HTTP_METHOD_DELETE, component); + ogs_free(component); + } else if (ogs_list_first(&as_state->delete_certificates) != NULL) { + char *component; + resource_id_node_t *delete_cert = ogs_list_first(&as_state->delete_certificates); + ogs_debug("M3 client: Sending DELETE method for certificate [%s] to the Application Server [%s]", delete_cert->state, as_state->application_server->canonicalHostname); + component = ogs_msprintf("certificates/%s", delete_cert->state); + m3_client_as_state_requests(as_state, NULL, NULL, NULL, (char *)OGS_SBI_HTTP_METHOD_DELETE, component); + ogs_free(component); + } else if(ogs_list_first(&as_state->purge_content_hosting_cache) != NULL){ + purge_resource_id_node_t *purge_chc = ogs_list_first(&as_state->purge_content_hosting_cache); + ogs_assert(purge_chc); + ogs_assert(purge_chc->provisioning_session_id); + const char *component = ogs_msprintf("content-hosting-configurations/%s/purge", purge_chc->provisioning_session_id); + if(purge_chc->purge_regex) { + ogs_debug("M3 client: Sending cache purge operation for resource [%s] to the Application Server", purge_chc->provisioning_session_id); + m3_client_as_state_requests(as_state, purge_chc, "application/x-www-form-urlencoded", purge_chc->purge_regex, (char *)OGS_SBI_HTTP_METHOD_POST, component); + } else { + ogs_debug("M3 client: Sending Purge operation for cache [%s] to the Application Server", purge_chc->provisioning_session_id); + m3_client_as_state_requests(as_state, purge_chc, "application/x-www-form-urlencoded", NULL, (char *)OGS_SBI_HTTP_METHOD_POST, component); } + ogs_free(component); + } - component = ogs_msprintf("content-hosting-configurations/%s", upload_chc->state); - - if (chc_id_node) { - ogs_debug("M3 client: Sending PUT method to Application Server [%s] for Content Hosting Configuration: [%s]", as_state->application_server->canonicalHostname, upload_chc->state); - m3_client_as_state_requests(as_state, "application/json", data, (char *)OGS_SBI_HTTP_METHOD_PUT, component); - } else { - ogs_debug("M3 client: Sending POST method to Application Server [%s] for Content Hosting Configuration: [%s]", as_state->application_server->canonicalHostname, upload_chc->state); - m3_client_as_state_requests(as_state, "application/json", data, (char *)OGS_SBI_HTTP_METHOD_POST, component); - } - if (chc_with_af_unique_cert_id) OpenAPI_content_hosting_configuration_free(chc_with_af_unique_cert_id); - ogs_free(component); - cJSON_Delete(json); - } else if (ogs_list_first(&as_state->delete_content_hosting_configurations) != NULL) { - char *component; - resource_id_node_t *delete_chc = ogs_list_first(&as_state->delete_content_hosting_configurations); - ogs_debug("M3 client: Sending DELETE method for Content Hosting Configuration [%s] to the Application Server [%s]", delete_chc->state, as_state->application_server->canonicalHostname); - component = ogs_msprintf("content-hosting-configurations/%s", delete_chc->state); - m3_client_as_state_requests(as_state, NULL, NULL, (char *)OGS_SBI_HTTP_METHOD_DELETE, component); - ogs_free(component); - } else if (ogs_list_first(&as_state->delete_certificates) != NULL) { - char *component; - resource_id_node_t *delete_cert = ogs_list_first(&as_state->delete_certificates); - ogs_debug("M3 client: Sending DELETE method for certificate [%s] to the Application Server [%s]", delete_cert->state, as_state->application_server->canonicalHostname); - component = ogs_msprintf("certificates/%s", delete_cert->state); - m3_client_as_state_requests(as_state, NULL, NULL, (char *)OGS_SBI_HTTP_METHOD_DELETE, component); - ogs_free(component); - } else if (ogs_list_first(&as_state->purge_content_hosting_cache) != NULL) { - purge_resource_id_node_t *purge_chc = ogs_list_first(&as_state->purge_content_hosting_cache); - char *component = ogs_msprintf("content-hosting-configurations/%s/purge", purge_chc->state); - if(purge_chc->purge_regex) { - ogs_debug("M3 client: Sending cache purge operation for resource [%s] using filter [%s] to the Application Server", purge_chc->state, purge_chc->purge_regex); - } else { - ogs_debug("M3 client: Sending Purge operation for cache [%s] to the Application Server", purge_chc->state); - } - m3_client_as_state_requests(as_state, "application/x-www-form-urlencoded", purge_chc->purge_regex, (char *)OGS_SBI_HTTP_METHOD_POST, component); - ogs_free(component); - } } + void msaf_application_server_remove_all() { msaf_application_server_node_t *msaf_as = NULL, *next = NULL; @@ -310,7 +306,7 @@ static void msaf_application_server_remove(msaf_application_server_node_t *msaf_ ogs_free(msaf_as); } - static ogs_sbi_client_t * +static ogs_sbi_client_t * msaf_m3_client_init(const char *hostname, int port) { int rv; @@ -334,64 +330,71 @@ msaf_m3_client_init(const char *hostname, int port) return client; } - static int +static int m3_client_as_state_requests(msaf_application_server_state_node_t *as_state, - const char *type, const char *data, const char *method, - const char *component) + purge_resource_id_node_t *purge_node, + const char *type, const char *data, const char *method, + const char *component) { - ogs_sbi_request_t *request; - - request = ogs_sbi_request_new(); - request->h.method = ogs_strdup(method); - request->h.uri = ogs_msprintf("http://%s:%i/3gpp-m3/v1/%s", - as_state->application_server->canonicalHostname, - as_state->application_server->m3Port, component); - request->h.api.version = ogs_strdup("v1"); - if (data) { - request->http.content = ogs_strdup(data); - request->http.content_length = strlen(data); - } - if (type) - ogs_sbi_header_set(request->http.headers, "Content-Type", type); + ogs_sbi_request_t *request; + + request = ogs_sbi_request_new(); + request->h.method = ogs_strdup(method); + request->h.uri = ogs_msprintf("http://%s:%i/3gpp-m3/v1/%s", + as_state->application_server->canonicalHostname, + as_state->application_server->m3Port, component); + request->h.api.version = ogs_strdup("v1"); + if (data) { + request->http.content = ogs_strdup(data); + request->http.content_length = strlen(data); + } + if (type) + ogs_sbi_header_set(request->http.headers, "Content-Type", type); - if (as_state->client == NULL) { - as_state->client = msaf_m3_client_init( - as_state->application_server->canonicalHostname, - as_state->application_server->m3Port); - } + if (as_state->client == NULL) { + as_state->client = msaf_m3_client_init( + as_state->application_server->canonicalHostname, + as_state->application_server->m3Port); + } + client_request_info_t *request_info = ogs_calloc(1, sizeof(client_request_info_t)); + request_info->as_state = as_state; + request_info->purge_node = purge_node; - ogs_sbi_client_send_request(as_state->client, client_notify_cb, request, as_state); + ogs_sbi_client_send_request(as_state->client, client_notify_cb, request, request_info); - ogs_sbi_request_free(request); + ogs_sbi_request_free(request); - return 1; -} + return 1; +} - static int +static int client_notify_cb(int status, ogs_sbi_response_t *response, void *data) { - int rv; - msaf_event_t *event; - - if (status != OGS_OK) { - ogs_log_message( - status == OGS_DONE ? OGS_LOG_DEBUG : OGS_LOG_WARN, 0, - "client_notify_cb() failed [%d]", status); - return OGS_ERROR; - } - - ogs_assert(response); - - event = (msaf_event_t*)ogs_event_new(OGS_EVENT_SBI_CLIENT); - event->h.sbi.response = response; - event->application_server_state = data; - rv = ogs_queue_push(ogs_app()->queue, event); - if (rv !=OGS_OK) { - ogs_error("OGS Queue Push failed %d", rv); - ogs_sbi_response_free(response); - ogs_event_free(event); - return OGS_ERROR; - } + int rv; + client_request_info_t *client_request_info = data; + msaf_event_t *event; + + if (status != OGS_OK) { + ogs_log_message( + status == OGS_DONE ? OGS_LOG_DEBUG : OGS_LOG_WARN, 0, + "client_notify_cb() failed [%d]", status); + return OGS_ERROR; + } - return OGS_OK; + ogs_assert(response); + + event = (msaf_event_t*)ogs_event_new(OGS_EVENT_SBI_CLIENT); + event->h.sbi.response = response; + event->application_server_state = client_request_info->as_state; + event->purge_node = client_request_info->purge_node; + rv = ogs_queue_push(ogs_app()->queue, event); + if (rv !=OGS_OK) { + ogs_error("OGS Queue Push failed %d", rv); + ogs_sbi_response_free(response); + ogs_event_free(event); + return OGS_ERROR; + } + if (client_request_info->purge_node == NULL) ogs_free(client_request_info->purge_node); + ogs_free(client_request_info); + return OGS_OK; } diff --git a/src/5gmsaf/application-server-context.h b/src/5gmsaf/application-server-context.h index 267f591..38a9a38 100644 --- a/src/5gmsaf/application-server-context.h +++ b/src/5gmsaf/application-server-context.h @@ -28,7 +28,6 @@ typedef struct msaf_application_server_node_s { typedef struct msaf_application_server_state_node_s { ogs_lnode_t node; ogs_sbi_client_t *client; - ogs_sbi_stream_t *stream; msaf_application_server_node_t *application_server; ogs_list_t assigned_provisioning_sessions; ogs_list_t *current_certificates; @@ -50,10 +49,19 @@ typedef struct application_server_state_node_s { char *state; } resource_id_node_t; -typedef struct purge_resource_node_s { +typedef struct m1_purge_information_s { + int refs; + int purged_entries_total; + + ogs_sbi_stream_t *m1_stream; + ogs_sbi_message_t m1_message; +} m1_purge_information_t; + +typedef struct purge_resource_id_node_s { ogs_lnode_t node; - char *state; + char *provisioning_session_id; char *purge_regex; + m1_purge_information_t *m1_purge_info; } purge_resource_id_node_t; /** diff --git a/src/5gmsaf/certmgr.c b/src/5gmsaf/certmgr.c new file mode 100644 index 0000000..67e164e --- /dev/null +++ b/src/5gmsaf/certmgr.c @@ -0,0 +1,270 @@ +/* +License: 5G-MAG Public License (v1.0) +Author: Dev Audsin +Copyright: (C) 2022 British Broadcasting Corporation + +For full license terms please see the LICENSE file distributed with this +program. If this file is missing then the license can be retrieved from +https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +*/ + +#include "certmgr.h" + + +#define MAX_CHILD_PROCESS 16 +#define OGS_ARG_MAX 256 + +static ogs_proc_t process[MAX_CHILD_PROCESS]; +static int process_num = 0; + + +int server_cert_delete(char *certid) +{ + const char *commandLine[OGS_ARG_MAX]; + ogs_proc_t *current = NULL; + FILE *out = NULL; + char buf[OGS_HUGE_LEN]; + int ret = 0, out_return_code = 0; + char *command; + char *rv = NULL; + + command = ogs_msprintf("-c delete %s", certid); + + commandLine[0] = msaf_self()->config.certificateManager; + commandLine[1] = command; + commandLine[2] = NULL; + + current = &process[process_num++]; + ret = ogs_proc_create(commandLine, + ogs_proc_option_combined_stdout_stderr| + ogs_proc_option_inherit_environment, + current); + ogs_assert(ret == 0); + out = ogs_proc_stdout(current); + ogs_assert(out); + + while(fgets(buf, OGS_HUGE_LEN, out)) { + printf("%s", buf); + } + ret = ogs_proc_join(current, &out_return_code); + ogs_assert(ret == 0); + ret = ogs_proc_destroy(current); + ogs_assert(ret == 0); + ogs_free(command); + + return out_return_code; +} + +msaf_certificate_t *server_cert_retrieve(char *certid) +{ + const char *commandLine[OGS_ARG_MAX]; + ogs_proc_t *current = NULL; + FILE *out = NULL; + char buf[OGS_HUGE_LEN]; + char *cert = NULL; + int ret = 0, out_return_code = 0; + msaf_certificate_t *msaf_certificate = NULL; + char *command; + char *rv = NULL; + size_t cert_size = 0; + size_t cert_reserved = 0; + char *ts = NULL; + char *etag_cert = NULL; + char *etag=NULL; + char *buff = NULL; + char *certificate = NULL; + + command = ogs_msprintf("-c publiccert %s", certid); + + commandLine[0] = msaf_self()->config.certificateManager; + commandLine[1] = command; + commandLine[2] = NULL; + + current = &process[process_num++]; + ret = ogs_proc_create(commandLine, + ogs_proc_option_combined_stdout_stderr| + ogs_proc_option_inherit_environment, + current); + ogs_assert(ret == 0); + out = ogs_proc_stdout(current); + ogs_assert(out); + + cert = ogs_calloc(1, 4096); + cert_reserved = 4096; + + while(fgets(buf, OGS_HUGE_LEN, out)) { + cert_size += strlen (buf); + if(cert_size > cert_reserved - 1) { + cert_reserved +=4096; + cert = ogs_realloc(cert,cert_reserved); + } + strcat(cert,buf); + + } + + buff = ogs_strdup(cert); + ts = strtok_r(buff,":",&etag_cert); + etag = strtok_r(etag_cert,":",&certificate); + ret = ogs_proc_join(current, &out_return_code); + ogs_assert(ret == 0); + ret = ogs_proc_destroy(current); + ogs_assert(ret == 0); + ogs_free(command); + msaf_certificate = ogs_calloc(1, sizeof(msaf_certificate_t)); + ogs_assert(msaf_certificate); + + msaf_certificate->id = certid; + msaf_certificate->certificate = cert; + msaf_certificate->return_code = out_return_code; + + return msaf_certificate; +} + +int server_cert_set(char *cert_id, char *cert) +{ + const char *commandLine[OGS_ARG_MAX]; + ogs_proc_t *current = NULL; + FILE *in = NULL; + char *bufin; + int ret = 0, out_return_code = 0, rv = 0; + char *operation; + + operation = ogs_msprintf("-c setcert %s", cert_id); + + commandLine[0] = msaf_self()->config.certificateManager; + commandLine[1] = operation; + commandLine[2] = NULL; + + current = &process[process_num++]; + ret = ogs_proc_create(commandLine, + ogs_proc_option_inherit_environment, + current); + ogs_assert(ret == 0); + + in = ogs_proc_stdin(current); + ogs_assert(in); + + if(cert) + { + fprintf(in, "%s", cert); + } + + ret = ogs_proc_join(current, &out_return_code); + ogs_assert(ret == 0); + ret = ogs_proc_destroy(current); + ogs_assert(ret == 0); + ogs_free(operation); + return out_return_code; +} + + +msaf_certificate_t *server_cert_new(char *operation, char *operation_params) +{ + const char *commandLine[OGS_ARG_MAX]; + ogs_proc_t *current = NULL; + FILE *out = NULL; + FILE *in = NULL; + char buf[4096]; + char *cert; + int ret = 0, out_return_code = 0; + char *canonical_domain_name; + char *certificate; + msaf_certificate_t *msaf_certificate = NULL; + size_t cert_size = 0; + size_t cert_reserved = 0; + + msaf_application_server_node_t *msaf_as = NULL; + msaf_as = ogs_list_first(&msaf_self()->config.applicationServers_list); + canonical_domain_name = msaf_as->canonicalHostname; + + ogs_uuid_t uuid; + char *command; + char id[OGS_UUID_FORMATTED_LENGTH + 1]; + char *rv = NULL; + + ogs_uuid_get(&uuid); + ogs_uuid_format(id, &uuid); + + command = ogs_msprintf("-c %s %s %s", operation, id, canonical_domain_name); + + commandLine[0] = msaf_self()->config.certificateManager; + commandLine[1] = command; + commandLine[2] = NULL; + + current = &process[process_num++]; + ret = ogs_proc_create(commandLine, + ogs_proc_option_combined_stdout_stderr| + ogs_proc_option_inherit_environment, + current); + ogs_assert(ret == 0); + out = ogs_proc_stdout(current); + ogs_assert(out); + + cert = ogs_calloc(1, 4096); + cert_reserved = 4096; + + while(fgets(buf, OGS_HUGE_LEN, out)) { + cert_size += strlen (buf); + if(cert_size > cert_reserved - 1) { + cert_reserved =+ 4096; + cert = ogs_realloc(cert,cert_reserved); + } + strcat(cert,buf); + } + ret = ogs_proc_join(current, &out_return_code); + ogs_assert(ret == 0); + ret = ogs_proc_destroy(current); + ogs_assert(ret == 0); + ogs_free(command); + msaf_certificate = ogs_calloc(1, sizeof(msaf_certificate_t)); + ogs_assert(msaf_certificate); + + msaf_certificate->id = id; + msaf_certificate->certificate = cert; + msaf_certificate->return_code = out_return_code; + + return msaf_certificate; +} + +char *check_in_cert_list(char *canonical_domain_name) +{ + const char *commandLine[OGS_ARG_MAX]; + ogs_proc_t *current = NULL; + FILE *out = NULL; + char buf[OGS_HUGE_LEN]; + int ret = 0, out_return_code = 0; + char *certificate = NULL; + char *cert_id; + + char *operation; + + operation = ogs_msprintf("-c list"); + + commandLine[0] = msaf_self()->config.certificateManager; + commandLine[1] = operation; + commandLine[2] = NULL; + + current = &process[process_num++]; + ret = ogs_proc_create(commandLine, + ogs_proc_option_combined_stdout_stderr| + ogs_proc_option_inherit_environment, + current); + ogs_assert(ret == 0); + out = ogs_proc_stdout(current); + ogs_assert(out); + + while(fgets(buf, OGS_HUGE_LEN, out)) { + + if (str_match(buf, canonical_domain_name)) { + certificate = strtok_r(buf,"\t",&cert_id); + break; + } + } + + ret = ogs_proc_join(current, &out_return_code); + ogs_assert(ret == 0); + ret = ogs_proc_destroy(current); + ogs_assert(ret == 0); + ogs_free(operation); + return certificate; +} \ No newline at end of file diff --git a/src/5gmsaf/certmgr.h b/src/5gmsaf/certmgr.h new file mode 100644 index 0000000..181c2af --- /dev/null +++ b/src/5gmsaf/certmgr.h @@ -0,0 +1,43 @@ +/* +License: 5G-MAG Public License (v1.0) +Author: Dev Audsin +Copyright: (C) 2022 British Broadcasting Corporation + +For full license terms please see the LICENSE file distributed with this +program. If this file is missing then the license can be retrieved from +https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view + */ + +#ifndef MSAF_CERT_MGR_H +#define MSAF_CERT_MGR_H + +#include "context.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct msaf_certificate_s { + char *id; + char *certificate; + int return_code; +} msaf_certificate_t; + + +typedef struct msaf_assigned_certificate_s { + ogs_lnode_t node; + char *certificate_id; +} msaf_assigned_certificate_t; + +extern msaf_certificate_t *server_cert_new(char *operation, char *operation_params); +extern int server_cert_set(char *cert_id, char *cert); +extern msaf_certificate_t *server_cert_retrieve(char *certid); +extern char *check_in_cert_list(char *canonical_domain_name); +extern int server_cert_delete(char *certid); + +#ifdef __cplusplus +} +#endif + +#endif /* MSAF_CERT_MGR_H */ diff --git a/src/5gmsaf/context.c b/src/5gmsaf/context.c index 363a000..d0f8ccc 100644 --- a/src/5gmsaf/context.c +++ b/src/5gmsaf/context.c @@ -30,10 +30,15 @@ static int msaf_context_validation(void); static int free_ogs_hash_entry(void *free_ogs_hash_context, const void *key, int klen, const void *value); static void safe_ogs_free(void *memory); +static void msaf_context_server_addr_add(const char *server_addr); + + static void msaf_context_application_server_state_certificates_remove_all(void); static void msaf_context_application_server_state_content_hosting_configuration_remove_all(void); static void msaf_context_application_server_state_assigned_provisioning_sessions_remove_all(void); static void msaf_context_application_server_state_remove_all(void); +static void msaf_context_server_addr_remove_all(void); +static void msaf_context_server_addr_remove(msaf_context_server_addr_t *msaf_server_addr); /***** Public functions *****/ @@ -48,6 +53,8 @@ void msaf_context_init(void) ogs_list_init(&self->config.applicationServers_list); + ogs_list_init(&self->config.server_addr_list); + ogs_list_init(&self->application_server_states); self->provisioningSessions_map = ogs_hash_make(); @@ -56,6 +63,9 @@ void msaf_context_init(void) self->content_hosting_configuration_file_map = ogs_hash_make(); ogs_assert(self->content_hosting_configuration_file_map); + + msaf_server_response_cache_control_set(); + } void msaf_context_final(void) @@ -86,6 +96,16 @@ void msaf_context_final(void) if(self->config.certificate) ogs_free(self->config.certificate); + if (self->config.server_response_cache_control) + { + ogs_free(self->config.server_response_cache_control); + } + + if (self->config.certificateManager) + ogs_free(self->config.certificateManager); + + msaf_context_server_addr_remove_all(); + msaf_application_server_remove_all(); msaf_context_application_server_state_certificates_remove_all(); @@ -134,6 +154,8 @@ int msaf_context_parse_config(void) } } else if (!strcmp(msaf_key, "certificate")) { self->config.certificate = rebase_path(ogs_app()->file, ogs_yaml_iter_value(&msaf_iter)); + } else if (!strcmp(msaf_key, "certificateManager")) { + self->config.certificateManager = ogs_strdup(ogs_yaml_iter_value(&msaf_iter)); } else if (!strcmp(msaf_key, "contentHostingConfiguration")) { self->config.contentHostingConfiguration = rebase_path(ogs_app()->file, ogs_yaml_iter_value(&msaf_iter)); } else if (!strcmp(msaf_key, "applicationServers")) { @@ -164,7 +186,40 @@ int msaf_context_parse_config(void) } } msaf_application_server_add(canonical_hostname, url_path_prefix_format, m3_port); - } else if (!strcmp(msaf_key, "sbi")) { + } else if (!strcmp(msaf_key, "serverResponseCacheControl")) { + ogs_yaml_iter_t cc_iter, cc_array; + ogs_yaml_iter_recurse(&msaf_iter, &cc_array); + if (ogs_yaml_iter_type(&cc_array) == YAML_MAPPING_NODE) { + memcpy(&cc_iter, &cc_array, sizeof(ogs_yaml_iter_t)); + } else if (ogs_yaml_iter_type(&cc_array) == YAML_SEQUENCE_NODE) { + if (!ogs_yaml_iter_next(&cc_array)) + break; + ogs_yaml_iter_recurse(&cc_array, &cc_iter); + } else if (ogs_yaml_iter_type(&cc_array) == YAML_SCALAR_NODE) { + break; + } else + ogs_assert_if_reached(); + + int m1_provisioning_session_response_max_age = SERVER_RESPONSE_MAX_AGE; + int m1_content_hosting_configurations_response_max_age = SERVER_RESPONSE_MAX_AGE; + int m1_content_protocols_response_max_age = M1_CONTENT_PROTOCOLS_RESPONSE_MAX_AGE; + int m5_service_access_information_response_max_age = SERVER_RESPONSE_MAX_AGE; + while (ogs_yaml_iter_next(&cc_iter)) { + const char *cc_key = ogs_yaml_iter_key(&cc_iter); + ogs_assert(cc_key); + if (!strcmp(cc_key, "m1ProvisioningSessions")) { + m1_provisioning_session_response_max_age = ascii_to_long(ogs_yaml_iter_value(&cc_iter)); + } else if (!strcmp(cc_key, "m1ContentHostingConfigurations")) { + m1_content_hosting_configurations_response_max_age = ascii_to_long(ogs_yaml_iter_value(&cc_iter)); + } else if (!strcmp(cc_key, "m1ContentProtocols")) { + m1_content_protocols_response_max_age = ascii_to_long(ogs_yaml_iter_value(&cc_iter)); + } else if (!strcmp(cc_key, "m5ServiceAccessInformation")) { + m5_service_access_information_response_max_age = ascii_to_long(ogs_yaml_iter_value(&cc_iter)); + } + } + msaf_server_response_cache_control_set_from_config(m1_provisioning_session_response_max_age, m1_content_hosting_configurations_response_max_age, m1_content_protocols_response_max_age, m5_service_access_information_response_max_age); + + } else if (!strcmp(msaf_key, "sbi")) { if(!self->config.open5gsIntegration_flag) { ogs_list_t list, list6; ogs_socknode_t *node = NULL, *node6 = NULL; @@ -274,6 +329,7 @@ int msaf_context_parse_config(void) addr = NULL; for (i = 0; i < num; i++) { rv = ogs_addaddrinfo(&addr, family, hostname[i], port, 0); + msaf_context_server_addr_add(hostname[i]); ogs_assert(rv == OGS_OK); } @@ -482,6 +538,21 @@ static void msaf_context_delete_content_hosting_configuration(const char *resour } } +static void msaf_context_server_addr_remove_all() +{ + msaf_context_server_addr_t *msaf_server_addr = NULL, *next = NULL; + ogs_list_for_each_safe(&msaf_self()->config.server_addr_list, next, msaf_server_addr) + msaf_context_server_addr_remove(msaf_server_addr); + +} + +static void msaf_context_server_addr_remove(msaf_context_server_addr_t *msaf_server_addr) +{ + ogs_assert(msaf_server_addr); + ogs_list_remove(&msaf_self()->config.server_addr_list, msaf_server_addr); + ogs_free(msaf_server_addr); +} + static void msaf_context_application_server_state_certificates_remove_all(void) { ogs_info("Removing all certificates from all Application Servers"); @@ -628,8 +699,15 @@ msaf_context_provisioning_session_free(msaf_provisioning_session_t *provisioning if (provisioning_session->provisioningSessionId) ogs_free(provisioning_session->provisioningSessionId); if (provisioning_session->aspId) ogs_free(provisioning_session->aspId); if (provisioning_session->externalApplicationId) ogs_free(provisioning_session->externalApplicationId); + if (provisioning_session->provisioningSessionHash) ogs_free(provisioning_session->provisioningSessionHash); + if (provisioning_session->contentHostingConfiguration) OpenAPI_content_hosting_configuration_free(provisioning_session->contentHostingConfiguration); + if (provisioning_session->contentHostingConfigurationHash) ogs_free(provisioning_session->contentHostingConfigurationHash); + if (provisioning_session->serviceAccessInformation) OpenAPI_service_access_information_resource_free(provisioning_session->serviceAccessInformation); + if (provisioning_session->serviceAccessInformationHash) ogs_free(provisioning_session->serviceAccessInformationHash); + + ogs_free(provisioning_session); } @@ -647,5 +725,34 @@ msaf_context_content_hosting_configuration_file_map(char *provisioning_session_i return self->content_hosting_configuration_file_map; } +static void msaf_context_server_addr_add(const char *server_addr) { + msaf_context_server_addr_t *msaf_server_addr; + msaf_server_addr = ogs_calloc(1, sizeof(msaf_context_server_addr_t)); + ogs_assert(msaf_server_addr); + msaf_server_addr->server_addr = server_addr; + ogs_list_add(&self->config.server_addr_list, msaf_server_addr); + +} + +int msaf_context_server_name_set(void) { + + msaf_context_server_addr_t *msaf_server_addr; + struct sockaddr_in sa; + msaf_server_addr = ogs_list_first(&self->config.server_addr_list); + memset(&sa, 0, sizeof sa); + sa.sin_family = AF_INET; + inet_pton(AF_INET, msaf_server_addr->server_addr, &sa.sin_addr); + int res = getnameinfo((struct sockaddr*)&sa, sizeof(sa), + self->server_name, sizeof(self->server_name), + NULL, 0, NI_NAMEREQD); + if (res) { + printf("error: %d\n", res); + } + else + printf("node=%s\n", self->server_name); + + return 0; +} + /* vim:ts=8:sts=4:sw=4:expandtab: */ diff --git a/src/5gmsaf/context.h b/src/5gmsaf/context.h index 4bc26eb..1920759 100644 --- a/src/5gmsaf/context.h +++ b/src/5gmsaf/context.h @@ -12,6 +12,8 @@ program. If this file is missing then the license can be retrieved from #define MSAF_CONTEXT_H #include +#include +#include #include "ogs-sbi.h" #include "ogs-app.h" @@ -26,6 +28,7 @@ program. If this file is missing then the license can be retrieved from #include "provisioning-session.h" #include "application-server-context.h" #include "service-access-information.h" +#include "response-cache-control.h" #ifdef __cplusplus extern "C" { @@ -39,8 +42,11 @@ extern int __msaf_log_domain; typedef struct msaf_configuration_s { int open5gsIntegration_flag; ogs_list_t applicationServers_list; + ogs_list_t server_addr_list; // Nodes for this list are of type msaf_sbi_addr_t * char *contentHostingConfiguration; char *certificate; + char *certificateManager; + msaf_server_response_cache_control_t *server_response_cache_control; int number_of_application_servers; } msaf_configuration_t; @@ -49,14 +55,21 @@ typedef struct msaf_context_s { ogs_hash_t *provisioningSessions_map; ogs_list_t application_server_states; ogs_hash_t *content_hosting_configuration_file_map; + char server_name[NI_MAXHOST]; } msaf_context_t; +typedef struct msaf_server_addr_s { + ogs_lnode_t node; + const char *server_addr; +} msaf_context_server_addr_t; + extern void msaf_context_init(void); extern void msaf_context_final(void); extern msaf_context_t *msaf_self(void); extern int msaf_context_parse_config(void); extern void msaf_context_provisioning_session_free(msaf_provisioning_session_t *provisioning_session); +extern int msaf_context_server_name_set(void); #ifdef __cplusplus } diff --git a/src/5gmsaf/event.h b/src/5gmsaf/event.h index 81d3bcf..c424b0b 100644 --- a/src/5gmsaf/event.h +++ b/src/5gmsaf/event.h @@ -13,11 +13,8 @@ program. If this file is missing then the license can be retrieved from #include "ogs-proto.h" #include "ogs-sbi.h" - - -//#ifndef MSAF_CONTEXT_H #include "context.h" -//#endif + #ifdef __cplusplus extern "C" { @@ -36,10 +33,14 @@ typedef enum { typedef struct msaf_application_server_state_node_s msaf_application_server_state_node_t; +typedef struct purge_resource_id_node_s purge_resource_id_node_t; + typedef struct msaf_event_s { ogs_event_t h; int local_id; msaf_application_server_state_node_t *application_server_state; + purge_resource_id_node_t *purge_node; + ogs_pkbuf_t *pkbuf; diff --git a/src/5gmsaf/hash.c b/src/5gmsaf/hash.c new file mode 100644 index 0000000..db3d09c --- /dev/null +++ b/src/5gmsaf/hash.c @@ -0,0 +1,30 @@ +/* +License: 5G-MAG Public License (v1.0) +Author: Dev Audsin +Copyright: (C) 2022 British Broadcasting Corporation + +For full license terms please see the LICENSE file distributed with this +program. If this file is missing then the license can be retrieved from +https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +*/ + +#include "hash.h" + +char *calculate_hash(char *buf) { + const unsigned char *result = NULL; + size_t result_len = gnutls_hash_get_len(GNUTLS_DIG_SHA256); + gnutls_datum_t data; + static char hash[1024]; + size_t i; + data.data = (unsigned char *)buf; + data.size = strlen(buf); + result = ogs_calloc(1, result_len); + gnutls_fingerprint(GNUTLS_DIG_SHA256, &data, result, &result_len); + for (i = 0; i < result_len; i++) + { + sprintf(&(hash[i*2]), "%02x", result[i]); + } + hash[sizeof (hash) - 1] = '\0'; + ogs_free(result); + return hash; +} diff --git a/src/5gmsaf/hash.h b/src/5gmsaf/hash.h new file mode 100644 index 0000000..384f5b5 --- /dev/null +++ b/src/5gmsaf/hash.h @@ -0,0 +1,29 @@ +/* +License: 5G-MAG Public License (v1.0) +Author: Dev Audsin +Copyright: (C) 2022 British Broadcasting Corporation + +For full license terms please see the LICENSE file distributed with this +program. If this file is missing then the license can be retrieved from +https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +*/ + +#ifndef MSAF_HASH_H +#define MSAF_HASH_H + +#include +#include +#include "ogs-app.h" +#include "context.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern char *calculate_hash(char *buf); + +#ifdef __cplusplus +} +#endif + +#endif /* MSAF_HASH_H */ diff --git a/src/5gmsaf/init.c b/src/5gmsaf/init.c index c0274c2..10e9598 100644 --- a/src/5gmsaf/init.c +++ b/src/5gmsaf/init.c @@ -16,12 +16,18 @@ program. If this file is missing then the license can be retrieved from static ogs_thread_t *thread; static void msaf_main(void *data); +static int msaf_set_time(void); + + static int initialized = 0; int msaf_initialize() { int rv; + rv = msaf_set_time(); + if(rv != 0) return OGS_ERROR; + ogs_sbi_context_init(); msaf_context_init(); @@ -120,3 +126,20 @@ static void msaf_main(void *data) ogs_fsm_fini(&msaf_sm, 0); } + +static int msaf_set_time(void) +{ + if(ogs_env_set("TZ", "GMT") != OGS_OK) + { + ogs_error("Failed to set TZ to GMT"); + return OGS_ERROR; + } + + if(ogs_env_set("LC_TIME", "C") != OGS_OK) + { + ogs_error("Failed to set LC_TIME to C"); + return OGS_ERROR; + } + return OGS_OK; + +} diff --git a/src/5gmsaf/msaf-sm.c b/src/5gmsaf/msaf-sm.c index 84c61f5..8f32e8d 100644 --- a/src/5gmsaf/msaf-sm.c +++ b/src/5gmsaf/msaf-sm.c @@ -12,8 +12,9 @@ #include "ogs-sbi.h" #include "sbi-path.h" #include "context.h" - -static void report_purging_error(msaf_application_server_state_node_t *as_state, ogs_sbi_message_t *message, int status_code, const char *status_msg); +#include "certmgr.h" +#include "server.h" +#include "response-cache-control.h" void msaf_state_initial(ogs_fsm_t *s, msaf_event_t *e) { @@ -51,13 +52,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) switch (e->h.id) { case OGS_FSM_ENTRY_SIG: ogs_info("[%s] MSAF Running", ogs_sbi_self()->nf_instance->id); - { /* TODO: Remove this when M1 is active */ - msaf_provisioning_session_t *ps; - ps = msaf_provisioning_session_create("DOWNLINK", NULL, "5GMS-AF internal"); - ogs_info("Provisioning session = %s", ps->provisioningSessionId); - ogs_assert(msaf_self()->config.contentHostingConfiguration); - } - + msaf_context_server_name_set(); break; case OGS_FSM_EXIT_SIG: @@ -71,11 +66,9 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) rv = ogs_sbi_parse_header(&message, &request->h); if (rv != OGS_OK) { - ogs_error("ogs_sbi_parse_header() failed"); - ogs_assert(true == - ogs_sbi_server_send_error( - stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, - NULL, "cannot parse HTTP message", NULL)); + ogs_error("ogs_sbi_parse_header() failed"); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "cannot parse HTTP message", NULL, NULL)); + break; } @@ -119,62 +112,119 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) CASE("3gpp-m1") if (strcmp(message.h.api.version, "v2") != 0) { + char *error; ogs_error("Not supported version [%s]", message.h.api.version); - ogs_assert(true == - ogs_sbi_server_send_error( - stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, - &message, "Not supported version", NULL)); + + error = ogs_msprintf("Version [%s] not supported", message.h.api.version); + + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL)); + ogs_sbi_message_free(&message); + ogs_free(error); break; } SWITCH(message.h.resource.component[0]) + CASE("provisioning-sessions") SWITCH(message.h.method) CASE(OGS_SBI_HTTP_METHOD_POST) if (message.h.resource.component[1] && message.h.resource.component[2] && message.h.resource.component[3]) { - msaf_provisioning_session_t *msaf_provisioning_session; + msaf_provisioning_session_t *msaf_provisioning_session; + if (!strcmp(message.h.resource.component[2],"content-hosting-configuration") && !strcmp(message.h.resource.component[3],"purge")) { + { + ogs_hash_index_t *hi; + for (hi = ogs_hash_first(request->http.headers); + hi; hi = ogs_hash_next(hi)) { + if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { + if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/x-www-form-urlencoded")) { + char *err = NULL; + char *type = NULL; + type = (char *)ogs_hash_this_val(hi); + ogs_error("Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); + asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); + + ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL)); + ogs_sbi_message_free(&message); + return; + + } + } + } + } msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if (msaf_provisioning_session) { + if(msaf_provisioning_session) { // process the POST body purge_resource_id_node_t *purge_cache; msaf_application_server_state_node_t *as_state; - assigned_provisioning_sessions_node_t *assigned_provisioning_sessions_resource; - ogs_list_for_each(&msaf_provisioning_session->msaf_application_server_state_nodes, as_state) { - if (as_state->application_server && as_state->application_server->canonicalHostname) { - ogs_list_for_each(&as_state->assigned_provisioning_sessions,assigned_provisioning_sessions_resource) { - if (!strcmp(assigned_provisioning_sessions_resource->assigned_provisioning_session->provisioningSessionId, msaf_provisioning_session->provisioningSessionId)) { + assigned_provisioning_sessions_node_t *assigned_provisioning_sessions_resource; + const char *component = ogs_msprintf("%s/content-hosting-configuration/purge", message.h.resource.component[1]); + m1_purge_information_t *m1_purge_info = ogs_calloc(1, sizeof(m1_purge_information_t)); + m1_purge_info->m1_stream = stream; + m1_purge_info->m1_message = message; + + ogs_list_for_each(&msaf_provisioning_session->msaf_application_server_state_nodes, as_state) { + if(as_state->application_server && as_state->application_server->canonicalHostname) { + ogs_list_for_each(&as_state->assigned_provisioning_sessions,assigned_provisioning_sessions_resource){ + if(!strcmp(assigned_provisioning_sessions_resource->assigned_provisioning_session->provisioningSessionId, msaf_provisioning_session->provisioningSessionId)) { purge_cache = ogs_calloc(1, sizeof(purge_resource_id_node_t)); ogs_assert(purge_cache); - purge_cache->state = ogs_strdup(assigned_provisioning_sessions_resource->assigned_provisioning_session->provisioningSessionId); - if (request->http.content) + purge_cache->provisioning_session_id = ogs_strdup(assigned_provisioning_sessions_resource->assigned_provisioning_session->provisioningSessionId); + + purge_cache->m1_purge_info = m1_purge_info; + m1_purge_info->refs++; + if(request->http.content) purge_cache->purge_regex = ogs_strdup(request->http.content); + else + purge_cache->purge_regex = NULL; + if (ogs_list_first(&as_state->purge_content_hosting_cache) == NULL) ogs_list_init(&as_state->purge_content_hosting_cache); ogs_list_add(&as_state->purge_content_hosting_cache, purge_cache); - } - } - } + } else { + ogs_error("Provisioning Session [%s] is not assigned to an Application Server", message.h.resource.component[1]); + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] is not assigned to an Application Server", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session is not assigned to an Application Server.", err, NULL)); - as_state->stream = stream; + } + } + } else { + ogs_error("Provisioning Session [%s]: Unable to get information about Application Server", message.h.resource.component[1]); + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] : Unable to get information about Application Server", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Unable to get information about Application Server", err, NULL)); + } next_action_for_application_server(as_state); + ogs_free(component); + } + if (m1_purge_info->refs == 0) { + ogs_free(m1_purge_info); + // Send 204 back to M1 client + } } else { - ogs_error("Unable to retrieve the Provisioning Session"); + ogs_error("Unable to retrieve the Provisioning Session [%s]", message.h.resource.component[1]); + char *err = NULL; + asprintf(&err,"Provisioning session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL)); + } } + } else if (message.h.resource.component[1] && message.h.resource.component[2]) { msaf_provisioning_session_t *msaf_provisioning_session; if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if (msaf_provisioning_session) { + if(msaf_provisioning_session) { // process the POST body - cJSON *entry; + cJSON *entry; int rv; cJSON *chc; cJSON *content_hosting_config = cJSON_Parse(request->http.content); @@ -182,22 +232,22 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_debug("txt:%s", txt); cJSON_ArrayForEach(entry, content_hosting_config) { - if (!strcmp(entry->string, "entryPointPath")){ - if (!uri_relative_check(entry->valuestring)) { + if(!strcmp(entry->string, "entryPointPath")){ + if(!uri_relative_check(entry->valuestring)) { char *err = NULL; - asprintf(&err,"Entry Point Path does not match the regular expression."); - ogs_error("Entry Point Path does not match the regular expression."); - ogs_assert(true == ogs_sbi_server_send_error(stream, - 404, &message, - "Entry Point Path does not match the regular expression.", - err)); + asprintf(&err,"While creating the Content Hosting Configuration for the Provisioning Session [%s], entryPointPath does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring ); + ogs_error("While creating the Content Hosting Configuration for the Provisioning Session [%s], entryPointPath does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring); + + ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL)); + cJSON_Delete(content_hosting_config); - break; - } + break; } - } - if (msaf_provisioning_session->contentHostingConfiguration) { + } + } + + if(msaf_provisioning_session->contentHostingConfiguration) { OpenAPI_content_hosting_configuration_free(msaf_provisioning_session->contentHostingConfiguration); msaf_provisioning_session->contentHostingConfiguration = NULL; @@ -207,58 +257,136 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) OpenAPI_service_access_information_resource_free(msaf_provisioning_session->serviceAccessInformation); msaf_provisioning_session->serviceAccessInformation = NULL; } - + + rv = msaf_distribution_create(content_hosting_config, msaf_provisioning_session); - - if (rv) { + + if(rv){ + ogs_debug("Content Hosting Configuration created successfully"); msaf_application_server_state_set_on_post(msaf_provisioning_session); chc = msaf_get_content_hosting_configuration_by_provisioning_session_id(message.h.resource.component[1]); if (chc != NULL) { - ogs_sbi_response_t *response; char *text; - response = ogs_sbi_response_new(); + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, "m1 contentHostingConfiguration"); text = cJSON_Print(chc); - response->http.content_length = strlen(text); - response->http.content = text; - response->status = 201; - ogs_sbi_header_set(response->http.headers, "Content-Type", "application/json"); - ogs_sbi_header_set(response->http.headers, "Location", request->h.uri); + nf_server_populate_response(response, strlen(text), text, 201); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); cJSON_Delete(chc); cJSON_Delete(content_hosting_config); } else { - char *err = NULL; - ogs_error("Unable to retrieve the Content Hosting Configuration"); - asprintf(&err,"Unable to retrieve the Content Hosting Configuration"); - ogs_error("Unable to retrieve the Content Hosting Configuration"); - ogs_assert(true == ogs_sbi_server_send_error(stream, - 404, &message, - "Unable to retrieve the Content Hosting Configuration", - err)); + char *err = NULL; + ogs_error("Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); + asprintf(&err,"Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL)); } + + } else { char *err = NULL; - ogs_error("Failed to populate Content Hosting Configuration"); - asprintf(&err,"Creation of the Content Hosting Configuration failed."); - ogs_error("Creation of the Content Hosting Configuration failed."); - ogs_assert(true == ogs_sbi_server_send_error(stream, - 404, &message, - "Creation of the Content Hosting Configuration failed.", - err)); + + ogs_error("Failed to populate Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); + asprintf(&err,"Creation of the Content Hosting Configuration failed for the Provisioning Session [%s]", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 500, 2, &message, "Creation of the Content Hosting Configuration failed.", err, NULL)); + + } + + } else { + char *err = NULL; + asprintf(&err,"Provisioning session [%s]does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL)); + + + } + + } + if (!strcmp(message.h.resource.component[2],"certificates")) { + ogs_info("POST certificates"); + ogs_hash_index_t *hi; + char *canonical_domain_name; + char *cert; + int csr = 0; + + { + for (hi = ogs_hash_first(request->http.params); + hi; hi = ogs_hash_next(hi)) { + if (!ogs_strcasecmp(ogs_hash_this_key(hi), "csr")) { + csr = 1; + break; + } + } + } + + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if (msaf_provisioning_session) { + if (csr) { + + msaf_certificate_t *csr_cert; + char *location; + csr_cert = server_cert_new("newcsr", NULL); + ogs_sbi_response_t *response; + location = ogs_msprintf("%s/%s", request->h.uri, csr_cert->id); + response = nf_server_new_response(location, "application/x-pem-file", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, "m1 contentHostingConfiguration"); + + response->http.content_length = strlen(csr_cert->certificate); + response->http.content = ogs_strdup(csr_cert->certificate); + response->status = 200; + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + ogs_free(location); + ogs_free(csr_cert->certificate); + ogs_free(csr_cert); + + return; + } + if (ogs_list_first(&msaf_provisioning_session->msaf_application_servers) == NULL) { + msaf_application_server_node_t *msaf_as = NULL; + msaf_as = ogs_list_first(&msaf_self()->config.applicationServers_list); + canonical_domain_name = msaf_as->canonicalHostname; + ogs_list_init(&msaf_provisioning_session->msaf_application_server_state_nodes); + ogs_list_add(&msaf_provisioning_session->msaf_application_server_state_nodes, msaf_as); + } + ogs_info("canonical_domain_name): %s", canonical_domain_name); + cert = check_in_cert_list(canonical_domain_name); + if (cert != NULL) { + ogs_sbi_response_t *response; + char *location; + response = ogs_sbi_response_new(); + response->status = 200; + location = ogs_msprintf("%s/%s", request->h.uri, cert); + ogs_sbi_header_set(response->http.headers, "Location", location); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + ogs_free(location); + } else { + msaf_certificate_t *new_cert; + new_cert = server_cert_new("newcert", NULL); + ogs_sbi_response_t *response; + char *location; + response = ogs_sbi_response_new(); + response->status = 200; + location = ogs_msprintf("%s/%s", request->h.uri, new_cert->id); + ogs_sbi_header_set(response->http.headers, "Location", location); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + ogs_free(location); + ogs_free(new_cert); + } } else { char *err = NULL; - asprintf(&err,"Provisioning session does not exists."); - ogs_error("Provisioning session does not exists."); - ogs_assert(true == ogs_sbi_server_send_error(stream, - 404, &message, - "Provisioning session does not exists.", - err)); + asprintf(&err,"Provisioning session [%s] does not exists.", message.h.resource.component[1]); + ogs_error("Provisioning session [%s] does not exists.", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL)); + } @@ -272,13 +400,13 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) msaf_provisioning_session_t *msaf_provisioning_session; cJSON_ArrayForEach(entry, prov_sess) { - if (!strcmp(entry->string, "provisioningSessionType")){ + if(!strcmp(entry->string, "provisioningSessionType")){ provisioning_session_type = entry->valuestring; } - if (!strcmp(entry->string, "aspId")){ + if(!strcmp(entry->string, "aspId")){ asp_id = entry->valuestring; } - if (!strcmp(entry->string, "externalApplicationId")){ + if(!strcmp(entry->string, "externalApplicationId")){ external_app_id = entry->valuestring; } @@ -289,19 +417,15 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_sbi_response_t *response; char *text; char *location; - response = ogs_sbi_response_new(); - text = cJSON_Print(provisioning_session); - response->http.content_length = strlen(text); - response->http.content = text; - response->status = 201; - ogs_sbi_header_set(response->http.headers, "Content-Type", "application/json"); - + text = cJSON_Print(provisioning_session); if (request->h.uri[strlen(request->h.uri)-1] != '/') { location = ogs_msprintf("%s/%s", request->h.uri,msaf_provisioning_session->provisioningSessionId); } else { location = ogs_msprintf("%s%s", request->h.uri,msaf_provisioning_session->provisioningSessionId); } - ogs_sbi_header_set(response->http.headers, "Location", location); + response = nf_server_new_response(location, "application/json", msaf_provisioning_session->provisioningSessionReceived, msaf_provisioning_session->provisioningSessionHash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, "m1 provisioningSession"); + + nf_server_populate_response(response, strlen(text), text, 201); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); ogs_free(location); @@ -311,17 +435,114 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; asprintf(&err,"Creation of the Provisioning session failed."); ogs_error("Creation of the Provisioning session failed."); - ogs_assert(true == ogs_sbi_server_send_error(stream, - 404, &message, - "Creation of the Provisioning session failed.", - err)); + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Creation of the Provisioning session failed.", err, NULL)); + } } break; CASE(OGS_SBI_HTTP_METHOD_GET) - if (message.h.resource.component[1]) { + if (message.h.resource.component[1] && message.h.resource.component[2] && message.h.resource.component[3]) { + if (!strcmp(message.h.resource.component[2],"certificates") ) { + msaf_provisioning_session_t *msaf_provisioning_session; + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if (msaf_provisioning_session) { + msaf_certificate_t *cert; + ogs_sbi_response_t *response; + + cert = server_cert_retrieve(message.h.resource.component[3]); + + if(!cert) { + ogs_error("unable to retrieve certificate [%s]", message.h.resource.component[3]); + return; + } + + response = ogs_sbi_response_new(); + if(!cert->return_code) { + response->http.content_length = strlen(cert->certificate); + response->http.content = ogs_strdup(cert->certificate); + response->status = 200; + ogs_sbi_header_set(response->http.headers, "Content-Type", "application/x-pem-file"); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + } else if(cert->return_code == 4){ + char *err = NULL; + asprintf(&err,"Certificate [%s] does not exists.", cert->id); + ogs_error("Certificate [%s] does not exists.", cert->id); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exists.", err, NULL)); + + } else if(cert->return_code == 8){ + char *err = NULL; + asprintf(&err,"Certificate [%s] not yet available.", cert->id); + ogs_error("Certificate [%s] not yet available.", cert->id); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate not yet available.", err, NULL)); + + + + } else { + char *err = NULL; + asprintf(&err,"Certificate [%s] management problem.", cert->id); + ogs_error("Certificate [%s] management problem.", cert->id); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL)); + + + } + ogs_free(cert->certificate); + ogs_free(cert); + + } else { + char *err = NULL; + asprintf(&err,"Provisioning session [%s] is not available.", message.h.resource.component[1]); + ogs_error("Provisioning session [%s] is not available.", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exists.", err, NULL)); + + + } + } + } + else + if (message.h.resource.component[1] && message.h.resource.component[2]) { + msaf_provisioning_session_t *msaf_provisioning_session; + if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if(msaf_provisioning_session) { + cJSON *chc; + chc = msaf_get_content_hosting_configuration_by_provisioning_session_id(message.h.resource.component[1]); + if (chc != NULL) { + ogs_sbi_response_t *response; + char *text; + text = cJSON_Print(chc); + + response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, "m1 contentHostingConfiguration"); + ogs_assert(response); + nf_server_populate_response(response, strlen(text), text, 200); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + + cJSON_Delete(chc); + } else { + char *err = NULL; + ogs_error("Provisioning Session [%s]: Unable to retrieve the Content Hosting Configuration", message.h.resource.component[1]); + asprintf(&err,"Provisioning Session [%s]: Unable to retrieve the Content Hosting Configuration", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL)); + + + + } + + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL)); + + } + + } + + } else if (message.h.resource.component[1]) { msaf_provisioning_session_t *msaf_provisioning_session = NULL; cJSON *provisioning_session = NULL; @@ -332,35 +553,35 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) if (provisioning_session && msaf_provisioning_session && !msaf_provisioning_session->marked_for_deletion) { ogs_sbi_response_t *response; char *text; - response = ogs_sbi_response_new(); text = cJSON_Print(provisioning_session); - response->http.content_length = strlen(text); - response->http.content = text; - response->status = 200; - ogs_sbi_header_set(response->http.headers, "Content-Type", "application/json"); - + + response = nf_server_new_response(NULL, "application/json", msaf_provisioning_session->provisioningSessionReceived, msaf_provisioning_session->provisioningSessionHash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, "m1 provisioningSession"); + + nf_server_populate_response(response, strlen(text), text, 200); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); cJSON_Delete(provisioning_session); } else { char *err = NULL; - asprintf(&err,"Provisioning session is not available."); - ogs_error("Provisioning session is not available."); - ogs_assert(true == ogs_sbi_server_send_error(stream, - 404, &message, - "Provisioning session is not available.", - err)); + asprintf(&err,"Provisioning Session [%s] is not available.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] is not available.", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL)); } } break; - + CASE(OGS_SBI_HTTP_METHOD_PUT) if (message.h.resource.component[1] && message.h.resource.component[2]) { + + ogs_info("PUT: %s", message.h.resource.component[1]); msaf_provisioning_session_t *msaf_provisioning_session; - if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if (msaf_provisioning_session) { + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if(msaf_provisioning_session) { + ogs_info("PUT: with msaf_provisioning_session: %s", message.h.resource.component[1]); + if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { + // process the POST body cJSON *entry; int rv; @@ -369,22 +590,21 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_debug("txt:%s", txt); cJSON_ArrayForEach(entry, content_hosting_config) { - if (!strcmp(entry->string, "entryPointPath")){ - if (!uri_relative_check(entry->valuestring)) { - char *err = NULL; - asprintf(&err,"Entry Point Path does not match the regular expression."); - ogs_error("Entry Point Path does not match the regular expression."); - ogs_assert(true == ogs_sbi_server_send_error(stream, - 404, &message, - "Entry Point Path does not match the regular expression.", - err)); + if(!strcmp(entry->string, "entryPointPath")){ + if(!uri_relative_check(entry->valuestring)) { + char *err = NULL; + asprintf(&err,"While updating the Content Hosting Configuration for the Provisioning Session [%s], Entry Point Path does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring ); + ogs_error("While updating the Content Hosting Configuration for the provisioning Session [%s], Entry Point Path does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring); + + ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL)); + cJSON_Delete(content_hosting_config); break; } } } - if (msaf_provisioning_session->contentHostingConfiguration) { + if(msaf_provisioning_session->contentHostingConfiguration) { OpenAPI_content_hosting_configuration_free(msaf_provisioning_session->contentHostingConfiguration); msaf_provisioning_session->contentHostingConfiguration = NULL; @@ -395,9 +615,11 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) msaf_provisioning_session->serviceAccessInformation = NULL; } + rv = msaf_distribution_create(content_hosting_config, msaf_provisioning_session); - if (rv) { + if(rv){ + msaf_application_server_state_update(msaf_provisioning_session); ogs_debug("Content Hosting Configuration updated successfully"); @@ -413,43 +635,163 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { char *err = NULL; - ogs_error("Failed to update Content Hosting Configuration"); - asprintf(&err,"Update to Content Hosting Configuration failed."); + ogs_error("Provisioning Session [%s]: Failed to update the Content Hosting Configuration.", message.h.resource.component[1]); + asprintf(&err,"Provisioning Session [%s]: Update to Content Hosting Configuration failed.", message.h.resource.component[1]); ogs_error("Update of the Content Hosting Configuration failed."); - ogs_assert(true == ogs_sbi_server_send_error(stream, - 404, &message, - "Creation of the Content Hosting Configuration failed.", - err)); + + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Failed to update the contentHostingConfiguration.", err, NULL)); } + } + if (message.h.resource.component[1] && !strcmp(message.h.resource.component[2],"certificates") && message.h.resource.component[3]) { + char *cert_id; + char *cert; + int rv; + ogs_sbi_response_t *response; + msaf_provisioning_session_t *msaf_provisioning_session; + + { + ogs_hash_index_t *hi; + for (hi = ogs_hash_first(request->http.headers); + hi; hi = ogs_hash_next(hi)) { + if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { + if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/x-pem-file")) { + char *err = NULL; + char *type = NULL; + type = (char *)ogs_hash_this_val(hi); + ogs_error("Unsupported Media Type: received type: %s, should have been application/x-pem-file", type); + asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-pem-file", type); + + ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL)); + ogs_sbi_message_free(&message); + return; + + } + } + } + } - } else { - char *err = NULL; - asprintf(&err,"Provisioning session does not exists."); - ogs_error("Provisioning session does not exists."); - ogs_assert(true == ogs_sbi_server_send_error(stream, - 404, &message, - "Provisioning session does not exists.", - err)); + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + + if(msaf_provisioning_session) { + cert_id = message.h.resource.component[3]; + cert = ogs_strdup(request->http.content); + rv = server_cert_set(cert_id, cert); + // response = ogs_sbi_response_new(); + + if (rv == 0){ + + response = ogs_sbi_response_new(); + response->status = 204; + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + } else if (rv == 3 ) { + + char *err = NULL; + ogs_error("A server certificate with id [%s] already exist", cert_id); + asprintf(&err,"A server certificate with id [%s] already exist", cert_id); + ogs_assert(true == nf_server_send_error(stream, 403, 3, &message, "A server certificate already exist.", err, NULL)); + + } else if(rv == 4) { + char *err = NULL; + ogs_error("Server certificate with id [%s] does not exist", cert_id); + asprintf(&err,"Server certificate with id [%s] does not exist", cert_id); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Server certificate does not exist.", err, NULL)); + + } else if(rv == 5) { + char *err = NULL; + ogs_error("CSR was never generated for this certificate Id [%s]", cert_id); + asprintf(&err,"CSR was never generated for this certificate Id [%s]", cert_id); + ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "CSR was never generated for the certificate.", err, NULL)); + + + } else if(rv == 6) { + char *err = NULL; + ogs_error("The public certificate [%s] provided does not match the key", cert_id); + asprintf(&err,"The public certificate [%s] provided does not match the key", cert_id); + ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "The public certificate provided does not match the key.", err, NULL)); + + } else { + char *err = NULL; + ogs_error("There was a certificate management problem for the certificate id [%s]", cert_id); + asprintf(&err,"There was a certificate management problem for the certificate id [%s].", cert_id); + + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "There was a certificate management problem.", err, NULL)); + + + } + ogs_free(cert); + } } + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL)); + } + + } break; - + CASE(OGS_SBI_HTTP_METHOD_DELETE) - if (message.h.resource.component[1]) { + + if (message.h.resource.component[1] && !strcmp(message.h.resource.component[2],"certificates") && message.h.resource.component[3]) { + ogs_sbi_response_t *response; + msaf_provisioning_session_t *provisioning_session = NULL; + provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if (provisioning_session) { + int rv; + rv = server_cert_delete(message.h.resource.component[3]); + if ((rv == 0) || (rv == 8)){ + + response = ogs_sbi_response_new(); + response->status = 204; + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + } else if (rv == 4 ) { + char *err = NULL; + asprintf(&err,"Certificate [%s] does not exist.", message.h.resource.component[3]); + ogs_error("Certificate [%s] does not exist.", message.h.resource.component[3]); + + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exist.", err, NULL)); + + } else { + char *err = NULL; + asprintf(&err,"Certificate management problem for certificate [%s].", message.h.resource.component[3]); + ogs_error("Certificate management problem."); + + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL)); + + + } + + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL)); + + + } + } else + + if (message.h.resource.component[1]) { ogs_sbi_response_t *response; msaf_provisioning_session_t *provisioning_session = NULL; provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if (!provisioning_session || provisioning_session->marked_for_deletion){ + if(!provisioning_session || provisioning_session->marked_for_deletion){ char *err = NULL; - ogs_error("Provisioning session either not found or already marked for deletion."); - ogs_assert(true == ogs_sbi_server_send_error(stream, - 404, &message, - "Unable to find the Provisioning session or it is marked for deletion already.", - err)); + asprintf(&err,"Provisioning session [%s] either not found or already marked for deletion.", message.h.resource.component[1]); + + ogs_error("Provisioning session [%s] either not found or already marked for deletion.",message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session either not found or already marked for deletion..", err, NULL)); + } else { provisioning_session->marked_for_deletion = 1; @@ -465,37 +807,39 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } } + break; DEFAULT - ogs_error("Invalid HTTP method [%s]", message.h.method); - ogs_assert(true == ogs_sbi_server_send_error(stream, - OGS_SBI_HTTP_STATUS_FORBIDDEN, - &message, "Invalid HTTP method", - message.h.method)); + ogs_error("Invalid HTTP method [%s]", message.h.method); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 0, &message, "Invalid HTTP method", message.h.method, NULL)); + END break; DEFAULT + char *err; ogs_error("Invalid resource name [%s]", message.h.resource.component[0]); - ogs_assert(true == - ogs_sbi_server_send_error(stream, - OGS_SBI_HTTP_STATUS_BAD_REQUEST, &message, - "Invalid resource name", - message.h.resource.component[0])); + asprintf(&err,"Invalid resource name [%s]", message.h.resource.component[0]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid resource name", err, NULL)); + END ogs_sbi_message_free(&message); break; CASE("3gpp-m5") if (strcmp(message.h.api.version, "v2") != 0) { + char *error; ogs_error("Not supported version [%s]", message.h.api.version); - ogs_assert(true == - ogs_sbi_server_send_error( - stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, - &message, "Not supported version", NULL)); + + error = ogs_msprintf("Version [%s] not supported", message.h.api.version); + + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL)); + ogs_sbi_message_free(&message); + ogs_free(error); + break; } SWITCH(message.h.resource.component[0]) @@ -503,33 +847,23 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) SWITCH(message.h.method) CASE(OGS_SBI_HTTP_METHOD_GET) cJSON *service_access_information; - - msaf_provisioning_session_t *msaf_provisioning_session = NULL; + msaf_provisioning_session_t *msaf_provisioning_session = NULL; msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if (!msaf_provisioning_session) { - char *err = NULL; + if(msaf_provisioning_session == NULL) { + char *err = NULL; asprintf(&err,"Provisioning Session [%s] not found.", message.h.resource.component[1]); - ogs_error("Client requested invalid Provisioning Session [%s]", message.h.resource.component[1]); - ogs_assert(true == ogs_sbi_server_send_error(stream, - 404, &message, - "Provisioning Session not found", - err)); - ogs_sbi_message_free(&message); - break; - } - - if (msaf_provisioning_session->serviceAccessInformation) { + ogs_error("Client requested invalid Provisioning Session [%s]", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Provisioning Session not found.", err, NULL)); + + } else if (msaf_provisioning_session->serviceAccessInformation) { service_access_information = msaf_context_retrieve_service_access_information(message.h.resource.component[1]); if (service_access_information != NULL) { ogs_sbi_response_t *response; char *text; - response = ogs_sbi_response_new(); text = cJSON_Print(service_access_information); - response->http.content_length = strlen(text); - response->http.content = text; - response->status = 200; - ogs_sbi_header_set(response->http.headers, "Content-Type", "application/json"); + response = nf_server_new_response(NULL, "application/json", msaf_provisioning_session->serviceAccessInformationCreated, msaf_provisioning_session->serviceAccessInformationHash, msaf_self()->config.server_response_cache_control->m5_service_access_information_response_max_age, "m5"); + nf_server_populate_response(response, strlen(text), text, 201); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); cJSON_Delete(service_access_information); @@ -537,47 +871,41 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; asprintf(&err,"Service Access Information for the Provisioning Session [%s] not found.", message.h.resource.component[1]); ogs_error("Client requested invalid Service Access Information for the Provisioning Session [%s]", message.h.resource.component[1]); - ogs_assert(true == ogs_sbi_server_send_error(stream, - 404, &message, - "Service Access Information not found", - err)); + + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL)); + + } } else { - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] has no Service Access Information associated with it.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] has no Service Access Information associated with it", message.h.resource.component[1]); - ogs_assert(true == ogs_sbi_server_send_error(stream, - 404, &message, - "Service Access Information not found", - err)); + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] has no Service Access Information associated with it.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] has no Service Access Information associated with it", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL)); + } break; DEFAULT ogs_error("Invalid HTTP method [%s]", message.h.method); - ogs_assert(true == ogs_sbi_server_send_error(stream, - OGS_SBI_HTTP_STATUS_FORBIDDEN, - &message, "Invalid HTTP method", - message.h.method)); + + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 1, &message, "Invalid HTTP method.", message.h.method, NULL)); + END break; DEFAULT ogs_error("Invalid resource name [%s]", message.h.resource.component[0]); - ogs_assert(true == - ogs_sbi_server_send_error(stream, - OGS_SBI_HTTP_STATUS_BAD_REQUEST, &message, - "Invalid resource name", - message.h.resource.component[0])); + + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid resource name.", message.h.resource.component[0], NULL)); + END ogs_sbi_message_free(&message); break; DEFAULT ogs_error("Invalid API name [%s]", message.h.service.name); - ogs_assert(true == - ogs_sbi_server_send_error(stream, - OGS_SBI_HTTP_STATUS_BAD_REQUEST, &message, - "Invalid API name", message.h.service.name)); - ogs_sbi_message_free(&message); + + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid API name.", message.h.service.name, NULL)); + END break; @@ -617,116 +945,174 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_assert(as_state); if (message.h.resource.component[1] && message.h.resource.component[2]) { + if (!strcmp(message.h.resource.component[2],"purge")) { SWITCH(message.h.method) CASE(OGS_SBI_HTTP_METHOD_POST) - - if (response->status == 204) { - - int elements_in_purge_list = 0; - purge_resource_id_node_t *content_hosting_cache, *next = NULL; - - ogs_list_for_each_safe(&as_state->purge_content_hosting_cache, next, content_hosting_cache){ - if (!strcmp(content_hosting_cache->state, message.h.resource.component[1])) - break; - } - - if (content_hosting_cache) { - - msaf_application_server_state_log(&as_state->purge_content_hosting_cache, "Purge Content Hosting Cache list"); - - if (content_hosting_cache->purge_regex) { - ogs_debug("Application Server [%s]: Purged cache pertainining to resource [%s] matching %s", as_state->application_server->canonicalHostname, content_hosting_cache->state, content_hosting_cache->purge_regex); - - } else { - ogs_debug("Application Server [%s]: Purged cache pertainining to resource [%s]", as_state->application_server->canonicalHostname, content_hosting_cache->state); - + purge_resource_id_node_t *purge_node = e->purge_node; + + if (response->status == 204 || response->status == 200) { + + purge_resource_id_node_t *content_hosting_cache, *next = NULL; + + if (response->status == 200) { + //parse the int in response body + //Add the integer to purge_node->m1_purge_info->purged_entries_total; + { + ogs_hash_index_t *hi; + for (hi = ogs_hash_first(request->http.headers); + hi; hi = ogs_hash_next(hi)) { + if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { + if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/json")) { + char *err = NULL; + char *type = NULL; + type = (char *)ogs_hash_this_val(hi); + ogs_error("Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); + asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); + + ogs_assert(true == nf_server_send_error(stream, 415, 2, &message, "Provisioning session does not exist.", err, NULL)); + ogs_sbi_message_free(&message); + return; + + + } + } + } } - if (content_hosting_cache->state) ogs_free(content_hosting_cache->state); - if (content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); - ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); - ogs_free(content_hosting_cache); - msaf_application_server_state_log(&as_state->purge_content_hosting_cache, "Purge Content Hosting Cache list"); - } + int purged_items_from_as = 0; + cJSON *entry; + cJSON *number_of_cache_entries = cJSON_Parse(response->http.content); + cJSON_ArrayForEach(entry, number_of_cache_entries) { + ogs_debug("Purged entries return %d\n", entry->valueint); + purged_items_from_as = entry->valueint; - ogs_list_for_each(&as_state->purge_content_hosting_cache, content_hosting_cache) { - if (!strcmp(content_hosting_cache->state, message.h.resource.component[1])) - elements_in_purge_list++; - } + } + purge_node->m1_purge_info->purged_entries_total += purged_items_from_as; - if (!elements_in_purge_list) { - ogs_sbi_response_t *response; - response = ogs_sbi_response_new(); - response->status = 200; - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(as_state->stream, response)); - } - - } else if (response->status == 200) { - - int elements_in_purge_list = 0; - purge_resource_id_node_t *content_hosting_cache, *next = NULL; + } + ogs_list_for_each_safe(&as_state->purge_content_hosting_cache, next, content_hosting_cache){ - - if (!strcmp(content_hosting_cache->state, message.h.resource.component[1])) + if(purge_node->purge_regex) + { + + if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id) && !strcmp(content_hosting_cache->purge_regex, purge_node->purge_regex)) + break; + } else if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id)) + { break; + } } - - if (content_hosting_cache) { - + if(content_hosting_cache){ + ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); + ogs_debug("M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); + + purge_node->m1_purge_info->refs--; + ogs_debug(" After decrement, M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); + if(!purge_node->m1_purge_info->refs){ + // send M1 response with total from purge_node->m1_purge_info->purged_entries_total + // ogs_free(purge_node->m1_purge_info); + ogs_sbi_response_t *response; + cJSON *purged_entries_total_json = cJSON_CreateNumber(purge_node->m1_purge_info->purged_entries_total); + char *purged_entries_total = cJSON_Print(purged_entries_total_json); + response = ogs_sbi_response_new(); + response->http.content_length = strlen(purged_entries_total); + response->http.content = purged_entries_total; + response->status = 200; + ogs_sbi_header_set(response->http.headers, "Content-Type", "application/json"); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(purge_node->m1_purge_info->m1_stream, response)); + + if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); + if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); + if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); + ogs_free(content_hosting_cache); + } msaf_application_server_state_log(&as_state->purge_content_hosting_cache, "Purge Content Hosting Cache list"); - - if (content_hosting_cache->purge_regex) { - ogs_debug("Application Server [%s] encountered a problem when purging its cache pertainining to resource [%s] for %s", as_state->application_server->canonicalHostname, content_hosting_cache->state, content_hosting_cache->purge_regex); - + + } + } + + + if((response->status == 404) || (response->status == 413) || (response->status == 414) || (response->status == 415) || (response->status == 422) || (response->status == 500) || (response->status == 503)) + { + char *error; + purge_resource_id_node_t *content_hosting_cache, *next = NULL; + cJSON *purge_cache_err = NULL; + if(response->http.content){ + purge_cache_err = cJSON_Parse(response->http.content); + char *txt = cJSON_Print(purge_cache_err); + ogs_debug("txt:%s", txt); + } + + if(response->status == 404) { + + ogs_error("Error message from the Application Server [%s] with response code [%d]: Cache not found\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 413) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Pay load too large\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 414) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: URI too long\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 415) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Unsupported media type\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 422) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Unprocessable Entity\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 500) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Internal server error\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 503) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Service Unavailable\n", as_state->application_server->canonicalHostname, response->status); + } else { + + ogs_error("Application Server [%s] sent unrecognised response code [%d]", as_state->application_server->canonicalHostname, response->status); + } + + if (purge_node->purge_regex) { + error = ogs_msprintf("Application Server possibly encountered problem with regex %s", purge_node->purge_regex); } else { - ogs_debug("Application Server [%s]: Failed to purge cache pertainining to resource [%s]", as_state->application_server->canonicalHostname, content_hosting_cache->state); - + error = ogs_msprintf("Application Server unable to process the contained instructions"); } - if (content_hosting_cache->state) ogs_free(content_hosting_cache->state); - if (content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); - ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); - ogs_free(content_hosting_cache); - msaf_application_server_state_log(&as_state->purge_content_hosting_cache, "Purge Content Hosting Cache list"); - } - - ogs_list_for_each(&as_state->purge_content_hosting_cache, content_hosting_cache) { - if (!strcmp(content_hosting_cache->state, message.h.resource.component[1])) - elements_in_purge_list++; - } - - if (!elements_in_purge_list) { - ogs_sbi_response_t *response; - response = ogs_sbi_response_new(); - response->status = 200; - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(as_state->stream, response)); - } - - } else if (response->status == 404) { - report_purging_error(as_state, &message, response->status, "Cache not found"); - } else if (response->status == 413) { - report_purging_error(as_state, &message, response->status, "Payload too large"); - } else if (response->status == 414){ - report_purging_error(as_state, &message, response->status, "URI too long"); - } else if (response->status == 415){ - report_purging_error(as_state, &message, response->status, "Unsupported media type"); - } else if (response->status == 422) { - report_purging_error(as_state, &message, response->status, "Unprocessable Entity"); - } else if (response->status == 500) { - report_purging_error(as_state, &message, response->status, "Internal server error"); - } else if (response->status == 503) { - report_purging_error(as_state, &message, response->status, "Service unavailable"); - } - next_action_for_application_server(as_state); + + + ogs_assert(true == nf_server_send_error( purge_node->m1_purge_info->m1_stream, + response->status, 3, &purge_node->m1_purge_info->m1_message, "Problem occured during cache purge", error, purge_cache_err)); + + ogs_list_for_each_safe(&as_state->purge_content_hosting_cache, next, content_hosting_cache){ + if (purge_node->purge_regex) { + if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id) && !strcmp(content_hosting_cache->purge_regex, purge_node->purge_regex)) { + + ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); + ogs_debug("M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); + if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); + if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); + if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); + ogs_free(content_hosting_cache); + + } + } else if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id)) { + + ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); + ogs_debug("M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); + if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); + if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); + if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); + ogs_free(content_hosting_cache); + + } + } + ogs_free(error); + cJSON_Delete(purge_cache_err); + + } + + next_action_for_application_server(as_state); break; END break; - } - } else if (message.h.resource.component[1]) { + + } + } else if (message.h.resource.component[1]) { + SWITCH(message.h.method) CASE(OGS_SBI_HTTP_METHOD_POST) @@ -736,10 +1122,10 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) resource_id_node_t *content_hosting_configuration; ogs_list_for_each(&as_state->upload_content_hosting_configurations,content_hosting_configuration) { - if (!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) + if(!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) break; } - if (content_hosting_configuration) { + if(content_hosting_configuration) { ogs_debug("Removing %s from upload_content_hosting_configurations", content_hosting_configuration->state); ogs_list_remove(&as_state->upload_content_hosting_configurations, content_hosting_configuration); @@ -748,36 +1134,36 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } } - if (response->status == 405){ - ogs_error("Content Hosting Configuration resource already exists at the specified path\n"); + if(response->status == 405){ + ogs_error("Content Hosting Configuration resource already exist at the specified path\n"); } - if (response->status == 413){ + if(response->status == 413){ ogs_error("Payload too large\n"); } - if (response->status == 414){ + if(response->status == 414){ ogs_error("URI too long\n"); } - if (response->status == 415){ + if(response->status == 415){ ogs_error("Unsupported media type\n"); } - if (response->status == 500){ + if(response->status == 500){ ogs_error("Internal server error\n"); } - if (response->status == 503){ + if(response->status == 503){ ogs_error("Service unavailable\n"); } next_action_for_application_server(as_state); break; CASE(OGS_SBI_HTTP_METHOD_PUT) - if (response->status == 200 || response->status == 204) { + if(response->status == 200 || response->status == 204) { ogs_debug("[%s] Method [%s] with Response [%d] recieved for Content Hosting Configuration [%s]", message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); resource_id_node_t *content_hosting_configuration; ogs_list_for_each(&as_state->upload_content_hosting_configurations,content_hosting_configuration){ - if (!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) + if(!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) break; } - if (content_hosting_configuration) { + if(content_hosting_configuration) { ogs_debug("Removing %s from upload_content_hosting_configurations", content_hosting_configuration->state); ogs_free(content_hosting_configuration->state); @@ -786,44 +1172,44 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } } - if (response->status == 404){ + if(response->status == 404){ ogs_error("Not Found\n"); } - if (response->status == 413){ + if(response->status == 413){ ogs_error("Payload too large\n"); } - if (response->status == 414){ + if(response->status == 414){ ogs_error("URI too long\n"); } - if (response->status == 415){ + if(response->status == 415){ ogs_error("Unsupported Media Type\n"); } - if (response->status == 500){ + if(response->status == 500){ ogs_error("Internal Server Error\n"); } - if (response->status == 503){ + if(response->status == 503){ ogs_error("Service Unavailable\n"); } next_action_for_application_server(as_state); break; CASE(OGS_SBI_HTTP_METHOD_DELETE) - if (response->status == 204) { + if(response->status == 204) { ogs_debug("[%s] Method [%s] with Response [%d] recieved for Content Hosting Configuration [%s]", message.h.resource.component[0], message.h.method, response->status,message.h.resource.component[1]); resource_id_node_t *content_hosting_configuration, *next = NULL; resource_id_node_t *delete_content_hosting_configuration, *node = NULL; - if (as_state->current_content_hosting_configurations) { + if(as_state->current_content_hosting_configurations) { ogs_list_for_each_safe(as_state->current_content_hosting_configurations, next, content_hosting_configuration){ - if (!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) + if(!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) break; } } - if (content_hosting_configuration) { + if(content_hosting_configuration) { msaf_application_server_state_log(as_state->current_content_hosting_configurations, "Current Content Hosting Configurations"); @@ -850,22 +1236,22 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } } - if (response->status == 404){ + if(response->status == 404){ ogs_error("Not Found\n"); } - if (response->status == 413){ + if(response->status == 413){ ogs_error("Payload too large\n"); } - if (response->status == 414){ + if(response->status == 414){ ogs_error("URI too long\n"); } - if (response->status == 415){ + if(response->status == 415){ ogs_error("Unsupported Media Type\n"); } - if (response->status == 500){ + if(response->status == 500){ ogs_error("Internal Server Error\n"); } - if (response->status == 503){ + if(response->status == 503){ ogs_error("Service Unavailable\n"); } next_action_for_application_server(as_state); @@ -882,7 +1268,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) SWITCH(message.h.method) CASE(OGS_SBI_HTTP_METHOD_GET) - if (response->status == 200) { + if(response->status == 200) { ogs_debug("[%s] Method [%s] with Response [%d] for Content Hosting Configuration operation [%s]", message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); @@ -941,7 +1327,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) if (message.h.resource.component[1]) { SWITCH(message.h.method) CASE(OGS_SBI_HTTP_METHOD_POST) - if (response->status == 201) { + if(response->status == 201) { ogs_debug("[%s] Method [%s] with Response [%d] recieved for certificate [%s]", message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); @@ -949,10 +1335,10 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) //Iterate upload_certs and find match strcmp resource component 0 ogs_list_for_each(&as_state->upload_certificates,certificate){ - if (!strcmp(certificate->state, message.h.resource.component[1])) + if(!strcmp(certificate->state, message.h.resource.component[1])) break; } - if (certificate) { + if(certificate) { ogs_debug("Removing certificate [%s] from upload_certificates", certificate->state); @@ -964,28 +1350,28 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) // ogs_free(upload_cert_id); } } - if (response->status == 405){ - ogs_error("Server Certificate resource already exists at the specified path\n"); + if(response->status == 405){ + ogs_error("Server Certificate resource already exist at the specified path\n"); } - if (response->status == 413){ + if(response->status == 413){ ogs_error("Payload too large\n"); } - if (response->status == 414){ + if(response->status == 414){ ogs_error("URI too long\n"); } - if (response->status == 415){ + if(response->status == 415){ ogs_error("Unsupported media type\n"); } - if (response->status == 500){ + if(response->status == 500){ ogs_error("Internal server error\n"); } - if (response->status == 503){ + if(response->status == 503){ ogs_error("Service unavailable\n"); } next_action_for_application_server(as_state); break; CASE(OGS_SBI_HTTP_METHOD_PUT) - if (response->status == 200 || response->status == 204) { + if(response->status == 200 || response->status == 204) { ogs_debug("[%s] Method [%s] with Response [%d] recieved for certificate [%s]", message.h.resource.component[0], message.h.method, response->status,message.h.resource.component[1]); @@ -996,11 +1382,11 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) //Iterate upload_certs and find match strcmp resource component 0 ogs_list_for_each(&as_state->upload_certificates,certificate){ - if (!strcmp(certificate->state, message.h.resource.component[1])) + if(!strcmp(certificate->state, message.h.resource.component[1])) break; } - if (!certificate){ + if(!certificate){ ogs_debug("Certificate %s not found in upload certificates", message.h.resource.component[1]); } else { ogs_debug("Removing certificate [%s] from upload_certificates", certificate->state); @@ -1010,43 +1396,43 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_free(certificate); } } - if (response->status == 404){ + if(response->status == 404){ ogs_error("Not Found\n"); } - if (response->status == 413){ + if(response->status == 413){ ogs_error("Payload too large\n"); } - if (response->status == 414){ + if(response->status == 414){ ogs_error("URI too long\n"); } - if (response->status == 415){ + if(response->status == 415){ ogs_error("Unsupported Media Type\n"); } - if (response->status == 500){ + if(response->status == 500){ ogs_error("Internal Server Error\n"); } - if (response->status == 503){ + if(response->status == 503){ ogs_error("Service Unavailable\n"); } next_action_for_application_server(as_state); break; CASE(OGS_SBI_HTTP_METHOD_DELETE) - if (response->status == 204) { + if(response->status == 204) { ogs_debug("[%s] Method [%s] with Response [%d] recieved for Certificate [%s]", message.h.resource.component[0], message.h.method, response->status,message.h.resource.component[1]); resource_id_node_t *certificate, *next = NULL; resource_id_node_t *delete_certificate, *node = NULL; - if (as_state->current_certificates) { + if(as_state->current_certificates) { ogs_list_for_each_safe(as_state->current_certificates, next, certificate){ - if (!strcmp(certificate->state, message.h.resource.component[1])) + if(!strcmp(certificate->state, message.h.resource.component[1])) break; } } - if (certificate) { + if(certificate) { msaf_application_server_state_log(as_state->current_certificates, "Current Certificates"); @@ -1061,7 +1447,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_list_for_each_safe(&as_state->delete_certificates, node, delete_certificate){ - if (!strcmp(delete_certificate->state, message.h.resource.component[1])) { + if(!strcmp(delete_certificate->state, message.h.resource.component[1])) { msaf_application_server_state_log(&as_state->delete_certificates, "Delete Certificates"); ogs_debug("Destroying Certificate: %s", delete_certificate->state); @@ -1073,22 +1459,22 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } } } - if (response->status == 404){ + if(response->status == 404){ ogs_error("Not Found\n"); } - if (response->status == 413){ + if(response->status == 413){ ogs_error("Payload too large\n"); } - if (response->status == 414){ + if(response->status == 414){ ogs_error("URI too long\n"); } - if (response->status == 415){ + if(response->status == 415){ ogs_error("Unsupported Media Type\n"); } - if (response->status == 500){ + if(response->status == 500){ ogs_error("Internal Server Error\n"); } - if (response->status == 503){ + if(response->status == 503){ ogs_error("Service Unavailable\n"); } next_action_for_application_server(as_state); @@ -1105,7 +1491,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) SWITCH(message.h.method) CASE(OGS_SBI_HTTP_METHOD_GET) - if (response->status == 200) { + if(response->status == 200) { ogs_debug("[%s] Method [%s] with Response [%d] received", message.h.resource.component[0], message.h.method, response->status); @@ -1141,7 +1527,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) cJSON_Delete(cert_array); } - if (response->status == 500) { + if (response->status == 500){ ogs_error("Received Internal Server error"); } if (response->status == 503) { @@ -1282,36 +1668,3 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } } -static void report_purging_error(msaf_application_server_state_node_t *as_state, ogs_sbi_message_t *message, int status_code, const char *status_msg) -{ - char *regex_purge = NULL; - char *error; - purge_resource_id_node_t *content_hosting_cache, *next = NULL; - - ogs_error("Error message from the Application Server [%s]: %s\n", as_state->application_server->canonicalHostname, status_msg); - - ogs_list_for_each_safe(&as_state->purge_content_hosting_cache, next, content_hosting_cache) { - if (!strcmp(content_hosting_cache->state, message->h.resource.component[1])) { - if (content_hosting_cache->state) ogs_free(content_hosting_cache->state); - if (content_hosting_cache->purge_regex) { - regex_purge = content_hosting_cache->purge_regex; - content_hosting_cache->purge_regex = NULL; - } - - ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); - ogs_free(content_hosting_cache); - } - } - if (regex_purge) { - error = ogs_msprintf("Application Server encountered a problem when purging its cache for the %s", regex_purge); - ogs_free(regex_purge); - } else { - error = ogs_msprintf("Application Server encountered a problem when purging its cache"); - } - - ogs_assert(true == ogs_sbi_server_send_error(as_state->stream, - status_code, message, "Application Server encountered a problem when purging its cache", error)); -} - -/* vim:ts=8:sts=4:sw=4:expandtab: -*/ diff --git a/src/5gmsaf/provisioning-session.c b/src/5gmsaf/provisioning-session.c index 40ea89b..2c76457 100644 --- a/src/5gmsaf/provisioning-session.c +++ b/src/5gmsaf/provisioning-session.c @@ -8,11 +8,13 @@ program. If this file is missing then the license can be retrieved from https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view */ +#include #include "provisioning-session.h" #include "application-server-context.h" #include "media-player-entry.h" #include "context.h" #include "utilities.h" +#include "hash.h" typedef struct free_ogs_hash_provisioning_session_s { char *provisioning_session; @@ -25,6 +27,8 @@ static int ogs_hash_do_cert_check(void *rec, const void *key, int klen, const vo static int free_ogs_hash_provisioning_session(void *rec, const void *key, int klen, const void *value); static char* url_path_create(const char* macro, const char* session_id, const msaf_application_server_node_t *msaf_as); static void tidy_relative_path_re(void); +static char *calculate_provisioning_session_hash(OpenAPI_provisioning_session_t *provisioning_session); +static char *calculate_service_access_information_hash(OpenAPI_service_access_information_resource_t *service_access_information); /***** Public functions *****/ @@ -57,32 +61,27 @@ msaf_content_hosting_configuration_with_af_unique_cert_id(msaf_provisioning_sess msaf_provisioning_session_t * msaf_provisioning_session_create(char *provisioning_session_type, char *asp_id, char *external_app_id) { - msaf_provisioning_session_t *msaf_provisioning_session; - char *media_player_entry; - + msaf_provisioning_session_t *msaf_provisioning_session; ogs_uuid_t uuid; char id[OGS_UUID_FORMATTED_LENGTH + 1]; - OpenAPI_provisioning_session_t *provisioning_session; - ogs_uuid_get(&uuid); ogs_uuid_format(id, &uuid); - provisioning_session = OpenAPI_provisioning_session_create(ogs_strdup(id), OpenAPI_provisioning_session_type_FromString(provisioning_session_type), (asp_id)?ogs_strdup(asp_id):NULL, ogs_strdup(external_app_id), NULL, NULL, NULL, NULL, NULL, NULL); msaf_provisioning_session = ogs_calloc(1, sizeof(msaf_provisioning_session_t)); ogs_assert(msaf_provisioning_session); - msaf_provisioning_session->provisioningSessionId = ogs_strdup(provisioning_session->provisioning_session_id); - msaf_provisioning_session->provisioningSessionType = provisioning_session->provisioning_session_type; msaf_provisioning_session->aspId = (provisioning_session->asp_id)?ogs_strdup(provisioning_session->asp_id):NULL; msaf_provisioning_session->externalApplicationId = ogs_strdup(provisioning_session->external_application_id); + msaf_provisioning_session->provisioningSessionReceived = time(NULL); + msaf_provisioning_session->provisioningSessionHash = ogs_strdup(calculate_provisioning_session_hash(provisioning_session)); msaf_provisioning_session->certificate_map = msaf_certificate_map(); ogs_hash_set(msaf_self()->provisioningSessions_map, ogs_strdup(msaf_provisioning_session->provisioningSessionId), OGS_HASH_KEY_STRING, msaf_provisioning_session); -#if 1 /* TODO: Remove when content hosting configuration is available via M1 interface */ +#if 0 /* TODO: Remove when content hosting configuration is available via M1 interface */ msaf_provisioning_session->contentHostingConfiguration = msaf_content_hosting_configuration_create(msaf_provisioning_session); media_player_entry = media_player_entry_create(msaf_provisioning_session->provisioningSessionId, msaf_provisioning_session->contentHostingConfiguration); ogs_assert(media_player_entry); @@ -375,11 +374,12 @@ msaf_distribution_create(cJSON *content_hosting_config, msaf_provisioning_sessio { OpenAPI_lnode_t *dist_config_node = NULL; OpenAPI_distribution_configuration_t *dist_config = NULL; - char *url_path; + char *url_path; char *domain_name; char *media_player_entry; static const char macro[] = "{provisioningSessionId}"; msaf_application_server_node_t *msaf_as = NULL; + char *content_hosting_config_to_hash = NULL; msaf_as = ogs_list_first(&msaf_self()->config.applicationServers_list); @@ -432,10 +432,19 @@ msaf_distribution_create(cJSON *content_hosting_config, msaf_provisioning_sessio if(media_player_entry) { provisioning_session->serviceAccessInformation = msaf_context_service_access_information_create(provisioning_session->provisioningSessionId, media_player_entry); + provisioning_session->serviceAccessInformationCreated = time(NULL); + provisioning_session->serviceAccessInformationHash = ogs_strdup(calculate_service_access_information_hash(provisioning_session->serviceAccessInformation)); } else { ogs_debug("Couldn't formulate serviceAccessInformation as media Player Entry is not formulated"); } provisioning_session->contentHostingConfiguration = content_hosting_configuration; + if(provisioning_session->contentHostingConfiguration) + { + content_hosting_config_to_hash = cJSON_Print(content_hosting_config); + provisioning_session->contentHostingConfigurationReceived = time(NULL); + + provisioning_session->contentHostingConfigurationHash = ogs_strdup(calculate_hash(content_hosting_config_to_hash)); + } ogs_free(url_path); return 1; @@ -599,6 +608,32 @@ int uri_relative_check(char *entry_point_path) /***** Private functions *****/ +static char *calculate_provisioning_session_hash(OpenAPI_provisioning_session_t *provisioning_session) +{ + cJSON *provisioning_sess = NULL; + char *provisioning_session_to_hash; + char *provisioning_session_hashed = NULL; + provisioning_sess = OpenAPI_provisioning_session_convertToJSON(provisioning_session); + provisioning_session_to_hash = cJSON_Print(provisioning_sess); + cJSON_Delete(provisioning_sess); + provisioning_session_hashed = calculate_hash(provisioning_session_to_hash); + ogs_free(provisioning_session_to_hash); + return provisioning_session_hashed; +} + +static char *calculate_service_access_information_hash(OpenAPI_service_access_information_resource_t *service_access_information) +{ + cJSON *service_access_info = NULL; + char *service_access_information_to_hash; + char *service_access_information_hashed = NULL; + service_access_info = OpenAPI_service_access_information_resource_convertToJSON(service_access_information); + service_access_information_to_hash = cJSON_Print(service_access_info); + cJSON_Delete(service_access_info); + service_access_information_hashed = calculate_hash(service_access_information_to_hash); + ogs_free(service_access_information_to_hash); + return service_access_information_hashed; +} + static int ogs_hash_do_cert_check(void *rec, const void *key, int klen, const void *value) { diff --git a/src/5gmsaf/provisioning-session.h b/src/5gmsaf/provisioning-session.h index c960ba3..d00a2f9 100644 --- a/src/5gmsaf/provisioning-session.h +++ b/src/5gmsaf/provisioning-session.h @@ -28,7 +28,15 @@ typedef struct msaf_provisioning_session_s { char *externalApplicationId; OpenAPI_content_hosting_configuration_t *contentHostingConfiguration; OpenAPI_service_access_information_resource_t *serviceAccessInformation; + time_t provisioningSessionReceived; + char *provisioningSessionHash; + time_t contentHostingConfigurationReceived; + char *contentHostingConfigurationHash; + time_t serviceAccessInformationCreated; + char *serviceAccessInformationHash; + ogs_list_t certificates; //Nodes for this list are msaf_assigned_certificate_t * ogs_hash_t *certificate_map; + ogs_list_t msaf_application_servers; // Nodes for this list are msaf_application_server_node_t * ogs_list_t msaf_application_server_state_nodes; //Nodes for this list are msaf_application_server_state_node_t * int marked_for_deletion; } msaf_provisioning_session_t; diff --git a/src/5gmsaf/response-cache-control.c b/src/5gmsaf/response-cache-control.c new file mode 100644 index 0000000..b095d12 --- /dev/null +++ b/src/5gmsaf/response-cache-control.c @@ -0,0 +1,38 @@ +/* +License: 5G-MAG Public License (v1.0) +Author: Dev Audsin +Copyright: (C) 2022 British Broadcasting Corporation + +For full license terms please see the LICENSE file distributed with this +program. If this file is missing then the license can be retrieved from +https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +*/ + +#include "context.h" +#include "response-cache-control.h" +/* +#define SERVER_RESPONSE_MAX_AGE 60 + +#define M1_CONTENT_PROTOCOLS_RESPONSE_MAX_AGE 86400 +*/ +void msaf_server_response_cache_control_set(void) +{ + msaf_server_response_cache_control_t *server_response_cache_control = NULL; + server_response_cache_control = ogs_calloc(1, sizeof(msaf_server_response_cache_control_t)); + ogs_assert(server_response_cache_control); + server_response_cache_control->m1_provisioning_session_response_max_age = SERVER_RESPONSE_MAX_AGE; + server_response_cache_control->m1_content_hosting_configurations_response_max_age = SERVER_RESPONSE_MAX_AGE; + server_response_cache_control->m1_content_protocols_response_max_age = M1_CONTENT_PROTOCOLS_RESPONSE_MAX_AGE; + server_response_cache_control->m5_service_access_information_response_max_age = SERVER_RESPONSE_MAX_AGE; + + msaf_self()->config.server_response_cache_control = server_response_cache_control; +} + +void msaf_server_response_cache_control_set_from_config(int m1_provisioning_session_response_max_age, int m1_content_hosting_configurations_response_max_age, int m1_content_protocols_response_max_age, int m5_service_access_information_response_max_age) +{ + msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age = m1_provisioning_session_response_max_age; + msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age = m1_content_hosting_configurations_response_max_age; + msaf_self()->config.server_response_cache_control->m1_content_protocols_response_max_age = m1_content_protocols_response_max_age; + msaf_self()->config.server_response_cache_control->m5_service_access_information_response_max_age = m5_service_access_information_response_max_age; +} + diff --git a/src/5gmsaf/response-cache-control.h b/src/5gmsaf/response-cache-control.h new file mode 100644 index 0000000..806f64d --- /dev/null +++ b/src/5gmsaf/response-cache-control.h @@ -0,0 +1,39 @@ +/* +License: 5G-MAG Public License (v1.0) +Author: Dev Audsin +Copyright: (C) 2022 British Broadcasting Corporation + +For full license terms please see the LICENSE file distributed with this +program. If this file is missing then the license can be retrieved from +https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +*/ + +#ifndef MSAF_RESPONSE_CACHE_CONTROL_H +#define MSAF_RESPONSE_CACHE_CONTROL_H + +#include "ogs-app.h" + +#define SERVER_RESPONSE_MAX_AGE 60 +#define M1_CONTENT_PROTOCOLS_RESPONSE_MAX_AGE 86400 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct msaf_server_response_cache_control_s { + int m1_provisioning_session_response_max_age; + int m1_content_hosting_configurations_response_max_age; + int m1_content_protocols_response_max_age; + int m5_service_access_information_response_max_age; +}msaf_server_response_cache_control_t; + +extern void msaf_server_response_cache_control_set(void); + +extern void msaf_server_response_cache_control_set_from_config(int m1_provisioning_session_response_max_age, int m1_content_hosting_configurations_response_max_age, int m1_content_protocols_response_max_age, int m5_service_access_information_response_max_age); + + +#ifdef __cplusplus +} +#endif + +#endif /* MSAF_RESPONSE_CACHE_CONTROL_H */ diff --git a/src/5gmsaf/server.c b/src/5gmsaf/server.c new file mode 100644 index 0000000..5254716 --- /dev/null +++ b/src/5gmsaf/server.c @@ -0,0 +1,263 @@ +/* +License: 5G-MAG Public License (v1.0) +Author: Dev Audsin +Copyright: (C) 2022 British Broadcasting Corporation + +For full license terms please see the LICENSE file distributed with this +program. If this file is missing then the license can be retrieved from +https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +*/ + +#include "ogs-sbi.h" +#include "server.h" +#include "utilities.h" +#include "version.h" + +static bool nf_server_send_problem( + ogs_sbi_stream_t *stream, OpenAPI_problem_details_t *problem); + +static ogs_sbi_response_t *nf_build_response( + ogs_sbi_message_t *message, int status); + +static bool nf_build_content( + ogs_sbi_http_message_t *http, ogs_sbi_message_t *message); + +static char *nf_build_json(ogs_sbi_message_t *message); + +ogs_sbi_response_t *nf_server_new_response(char *location, char *content_type, time_t last_modified, char *etag, int cache_control, char *interface) +{ + ogs_sbi_response_t *response = NULL; + char *server_api_info = NULL; + char *server = NULL; + + response = ogs_sbi_response_new(); + ogs_expect_or_return_val(response, NULL); + + if(content_type) + { + ogs_sbi_header_set(response->http.headers, "Content-Type", content_type); + } + + if(location) + { + ogs_sbi_header_set(response->http.headers, "Location", location); + } + + if(last_modified) + { + + ogs_sbi_header_set(response->http.headers, "Last-Modified", get_time(last_modified)); + } + + if(etag) + { + + ogs_sbi_header_set(response->http.headers, "ETag", etag); + } + + if(cache_control) + { + char *response_cache_control; + response_cache_control = ogs_msprintf("%d", cache_control); + ogs_sbi_header_set(response->http.headers, "Cache-Control: max-age=", response_cache_control); + ogs_free(response_cache_control); + } + + if(!interface){ + + server = ogs_msprintf("5GMSdAF-%s/%s %s/%s",msaf_self()->server_name, FIVE_API_RELEASE, MSAF_NAME, MSAF_VERSION); + + + } else if(!strcmp(interface, "m1 provisioningSession")) + { + + server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", _OpenAPI_provisioning_session_info_title, _OpenAPI_provisioning_session_info_version); + server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVE_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); + + } else if(!strcmp(interface, "m1 contentHostingConfiguration")) + { + + server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", _OpenAPI_content_hosting_configuration_info_title, _OpenAPI_content_hosting_configuration_info_version); + server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVE_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); + + } else if(!strcmp(interface, "m5")) + { + + server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", _OpenAPI_service_access_information_resource_info_title, _OpenAPI_service_access_information_resource_info_version); + server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVE_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); + + } else { + + server = ogs_msprintf("5GMSdAF-%s/%s %s/%s",msaf_self()->server_name, FIVE_API_RELEASE, MSAF_NAME, MSAF_VERSION); + } + + ogs_sbi_header_set(response->http.headers, "Server", server); + if(server_api_info) ogs_free(server_api_info); + ogs_free(server); + + return response; + + +} + +ogs_sbi_response_t *nf_server_populate_response(ogs_sbi_response_t *response, int content_length, char *content, int status) +{ + response->http.content_length = content_length; + response->http.content = content; + response->status = status; + return response; + +} + + + + + +static bool nf_server_send_problem( + ogs_sbi_stream_t *stream, OpenAPI_problem_details_t *problem) +{ + ogs_sbi_message_t message; + ogs_sbi_response_t *response = NULL; + + ogs_assert(stream); + ogs_assert(problem); + + memset(&message, 0, sizeof(message)); + + message.http.content_type = (char*)"application/problem+json"; + message.ProblemDetails = problem; + + response = nf_build_response(&message, problem->status); + ogs_assert(response); + + ogs_sbi_server_send_response(stream, response); + + return true; +} + + +bool nf_server_send_error(ogs_sbi_stream_t *stream, + int status, int number_of_components, ogs_sbi_message_t *message, + const char *title, const char *detail, cJSON * problem_detail) +{ + OpenAPI_problem_details_t problem; + OpenAPI_problem_details_t *problem_details = NULL; + + ogs_assert(stream); + + memset(&problem, 0, sizeof(problem)); + + if(problem_detail) { + problem_details = OpenAPI_problem_details_parseFromJSON(problem_detail); + problem.invalid_params = problem_details->invalid_params; + + } + + + if (message) { + int i; + problem.type = ogs_msprintf("/%s/%s", + message->h.service.name, message->h.api.version); + ogs_expect_or_return_val(problem.type, false); + + problem.instance = ogs_msprintf("/%s", message->h.resource.component[0]); + + for (i = 1; i <= number_of_components; i++) + { + ogs_free(problem.instance); + problem.instance = ogs_msprintf("%s/%s", problem.instance, message->h.resource.component[i]); + + } + ogs_expect_or_return_val(problem.instance, NULL); + } + if (status) { + problem.is_status = true; + problem.status = status; + } + problem.title = (char*)title; + problem.detail = (char*)detail; + + nf_server_send_problem(stream, &problem); + + if (problem.type) + ogs_free(problem.type); + if (problem.instance) + ogs_free(problem.instance); + if (problem.invalid_params) + OpenAPI_problem_details_free(problem_details); + + return true; +} + +ogs_sbi_response_t *nf_build_response( + ogs_sbi_message_t *message, int status) +{ + ogs_sbi_response_t *response = NULL; + + ogs_assert(message); + + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL); + + //response = ogs_sbi_response_new(); + ogs_expect_or_return_val(response, NULL); + + response->status = status; + + if (response->status != OGS_SBI_HTTP_STATUS_NO_CONTENT) { + ogs_expect_or_return_val(true == + nf_build_content(&response->http, message), NULL); + } + + if (message->http.location) { + ogs_sbi_header_set(response->http.headers, "Location", + message->http.location); + } + if (message->http.cache_control) + ogs_sbi_header_set(response->http.headers, "Cache-Control", + message->http.cache_control); + + return response; +} + +static bool nf_build_content( + ogs_sbi_http_message_t *http, ogs_sbi_message_t *message) +{ + ogs_assert(message); + ogs_assert(http); + + http->content = nf_build_json(message); + if (http->content) { + http->content_length = strlen(http->content); + if (message->http.content_type) { + ogs_sbi_header_set(http->headers, + OGS_SBI_CONTENT_TYPE, message->http.content_type); + } else { + ogs_sbi_header_set(http->headers, + OGS_SBI_CONTENT_TYPE, OGS_SBI_CONTENT_JSON_TYPE); + } + } + + return true; +} + +static char *nf_build_json(ogs_sbi_message_t *message) +{ + char *content = NULL; + cJSON *item = NULL; + + ogs_assert(message); + + if (message->ProblemDetails) { + item = OpenAPI_problem_details_convertToJSON(message->ProblemDetails); + ogs_assert(item); + } + if (item) { + content = cJSON_Print(item); + ogs_assert(content); + ogs_log_print(OGS_LOG_TRACE, "%s", content); + cJSON_Delete(item); + } + + return content; +} + diff --git a/src/5gmsaf/server.h b/src/5gmsaf/server.h new file mode 100644 index 0000000..d9efb4c --- /dev/null +++ b/src/5gmsaf/server.h @@ -0,0 +1,32 @@ +/* +License: 5G-MAG Public License (v1.0) +Author: Dev Audsin +Copyright: (C) 2022 British Broadcasting Corporation + +For full license terms please see the LICENSE file distributed with this +program. If this file is missing then the license can be retrieved from +https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view + */ + +#ifndef NF_SERVER_H +#define NF_SERVER_H + + #include "context.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +extern bool nf_server_send_error(ogs_sbi_stream_t *stream, + int status, int number_of_components, ogs_sbi_message_t *message, + const char *title, const char *detail, cJSON * problem_detail); + +extern ogs_sbi_response_t *nf_server_new_response(char *location, char *content_type, time_t last_modified, char *etag, int cache_control, char *interface); +extern ogs_sbi_response_t *nf_server_populate_response(ogs_sbi_response_t *response, int content_length, char *content, int status); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/5gmsaf/utilities.c b/src/5gmsaf/utilities.c index a2ad33c..ffe0b5b 100644 --- a/src/5gmsaf/utilities.c +++ b/src/5gmsaf/utilities.c @@ -13,8 +13,22 @@ program. If this file is missing then the license can be retrieved from #include #include #include +#include +#include #include "utilities.h" +char *get_time(time_t time_epoch) +{ + struct tm *ts; + static char buf[80]; + + /* Format and print the time, "ddd yyyy-mm-dd hh:mm:ss zzz" */ + ts = localtime(&time_epoch); + strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %Z", ts); + + return buf; +} + char *read_file(const char *filename) { FILE *f = NULL; @@ -40,6 +54,22 @@ char *read_file(const char *filename) } +int str_match(const char *line, const char *word_to_find) { + + char* p = strstr(line,word_to_find); + if ((p==line) || (p!=NULL && !isalnum((unsigned char)p[-1]))) + { + p += strlen(word_to_find); + if (!isalnum((unsigned char)*p)) + { + return 1; + } else { + return 0; + } + } + return 0; +} + char *get_path(const char *file) { char *path = NULL; @@ -82,5 +112,16 @@ long int ascii_to_long(const char *str) return ret; } +cJSON *create_cjson_number_object(char *name, int value) +{ + cJSON *item = NULL; + item = cJSON_CreateObject(); + if (cJSON_AddNumberToObject(item, name, value) == NULL) + { + ogs_error("Failed to create JSON object [%s] for integer value [%d]", name, value); + } + return item; +} + /* vim:ts=8:sts=4:sw=4:expandtab: */ diff --git a/src/5gmsaf/utilities.h b/src/5gmsaf/utilities.h index ccd45e9..0a69b1f 100644 --- a/src/5gmsaf/utilities.h +++ b/src/5gmsaf/utilities.h @@ -15,6 +15,7 @@ program. If this file is missing then the license can be retrieved from #include #include #include "ogs-app.h" +#include "context.h" #ifdef __cplusplus extern "C" { @@ -24,6 +25,8 @@ extern char *read_file(const char *filename); extern char *get_path(const char *file); extern char *rebase_path(const char *base, const char *file); extern long int ascii_to_long(const char *str); +extern int str_match(const char *line, const char *word_to_find); +extern char *get_time(time_t time_epoch); #ifdef __cplusplus } From ccc2c97aeca2b9b042bbf8dc55a966ca338f708d Mon Sep 17 00:00:00 2001 From: deva Date: Mon, 13 Feb 2023 10:52:51 +0000 Subject: [PATCH 04/48] Set correct header for the cache-control --- src/5gmsaf/server.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/5gmsaf/server.c b/src/5gmsaf/server.c index 5254716..2523a62 100644 --- a/src/5gmsaf/server.c +++ b/src/5gmsaf/server.c @@ -58,9 +58,9 @@ ogs_sbi_response_t *nf_server_new_response(char *location, char *content_type, t if(cache_control) { char *response_cache_control; - response_cache_control = ogs_msprintf("%d", cache_control); - ogs_sbi_header_set(response->http.headers, "Cache-Control: max-age=", response_cache_control); - ogs_free(response_cache_control); + response_cache_control = ogs_msprintf("max-age=%d", cache_control); + ogs_sbi_header_set(response->http.headers, "Cache-Control", response_cache_control); + ogs_free(response_cache_control); } if(!interface){ From 373523d2ab16f06ba98e87e83c521dc384c917ba Mon Sep 17 00:00:00 2001 From: David Waring Date: Wed, 15 Feb 2023 14:42:38 +0000 Subject: [PATCH 05/48] Add API information headers. --- meson.build | 3 +++ src/5gmsaf/api-info-head.mustache | 9 +++++++++ src/5gmsaf/generator-5gmsaf | 9 ++++++++- src/5gmsaf/meson.build | 7 ++++++- subprojects/patch_open5gs.sh | 29 ++++++++++++++++++++++++----- subprojects/rt-common-shared | 2 +- 6 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 src/5gmsaf/api-info-head.mustache diff --git a/meson.build b/meson.build index 72eb1d2..cf8744e 100644 --- a/meson.build +++ b/meson.build @@ -14,6 +14,9 @@ project('rt-5gms-application-function', 'c', 'c_std=gnu89', ], ) + +fiveg_api_release = '17' + sh_cmd = find_program('sh') patch_open5gs_result = run_command([sh_cmd, '-c', '"$MESON_SOURCE_ROOT/subprojects/patch_open5gs.sh" open5gs'], check: true, capture: false) open5gs_project=subproject('open5gs',required:true) diff --git a/src/5gmsaf/api-info-head.mustache b/src/5gmsaf/api-info-head.mustache new file mode 100644 index 0000000..a310f9d --- /dev/null +++ b/src/5gmsaf/api-info-head.mustache @@ -0,0 +1,9 @@ +#ifndef _{{#lambda.uppercase}}{{projectName}}{{/lambda.uppercase}}_API_H +#define _{{#lambda.uppercase}}{{projectName}}{{/lambda.uppercase}}_API_H + +#define {{#lambda.uppercase}}{{projectName}}{{/lambda.uppercase}}_BASE_PATH "{{basePath}}" +#define {{#lambda.uppercase}}{{projectName}}{{/lambda.uppercase}}_API_NAME "{{appName}}" +#define {{#lambda.uppercase}}{{projectName}}{{/lambda.uppercase}}_API_VERSION "{{appVersion}}" +#define {{#lambda.uppercase}}{{projectName}}{{/lambda.uppercase}}_API_DESCRIPTION "{{appDescription}}" + +#endif /* _{{#lambda.uppercase}}{{projectName}}{{/lambda.uppercase}}_API_H */ diff --git a/src/5gmsaf/generator-5gmsaf b/src/5gmsaf/generator-5gmsaf index 7bac86a..3c4fe8d 100755 --- a/src/5gmsaf/generator-5gmsaf +++ b/src/5gmsaf/generator-5gmsaf @@ -29,7 +29,7 @@ scriptdir=`cd "$scriptdir"; pwd` # Command line option defaults default_branch='REL-17' -default_apis="TS26512_M1_ProvisioningSessions TS26512_M1_ContentHostingProvisioning TS26512_M5_ServiceAccessInformation" +default_apis="TS26512_M1_ProvisioningSessions TS26512_M1_ContentHostingProvisioning TS26512_M1_ServerCertificatesProvisioning TS26512_M1_ContentProtocolsDiscovery M3_ContentHostingProvisioning M3_ServerCertificatesProvisioning TS26512_M5_ServiceAccessInformation" # Parse command line arguments ARGS=`getopt -n "$scriptname" -o 'a:b:h' -l 'api:,branch:,help' -s sh -- "$@"` @@ -109,6 +109,13 @@ destdir=`realpath -m "$scriptdir/openapi"` openapi_gen_dir=`realpath "$scriptdir/../../subprojects/open5gs/lib/sbi/support/20210629/openapi-generator"` sed "s@^templateDir:.*@templateDir: \"${openapi_gen_dir}/templates\"@" $openapi_gen_dir/config.yaml > $scriptdir/config.yaml +cp "${scriptdir}/"*.mustache "${openapi_gen_dir}/templates/" +cat >> $scriptdir/config.yaml << EOF +files: + api-info-head.mustache: + templateType: API + destinationFilename: -info.h +EOF # call the common generate_openapi script if [ ! -d "$scriptdir/openapi" ]; then diff --git a/src/5gmsaf/meson.build b/src/5gmsaf/meson.build index 574c970..531904d 100644 --- a/src/5gmsaf/meson.build +++ b/src/5gmsaf/meson.build @@ -172,7 +172,12 @@ libmsaf_gen_sources = ''' '''.split() gen_5gmsaf_openapi = find_program('sh') -openapi_gen_result = run_command([gen_5gmsaf_openapi,'-c','$MESON_SOURCE_ROOT/$MESON_SUBDIR/generator-5gmsaf'], check: true, capture: false) +openapi_gen_result = run_command([gen_5gmsaf_openapi,'-c','$MESON_SOURCE_ROOT/$MESON_SUBDIR/generator-5gmsaf', '-b', 'REL-'+fiveg_api_release], check: true, capture: false) + +version_conf = configuration_data() +version_conf.set_quoted('MSAF_VERSION', meson.project_version()) +version_conf.set_quoted('FIVEG_API_RELEASE', fiveg_api_release) +configure_file(output : 'msaf-version.h', configuration : version_conf) libmsaf_sources = libmsaf_dist_sources + libmsaf_gen_sources diff --git a/subprojects/patch_open5gs.sh b/subprojects/patch_open5gs.sh index d5012d5..5f90519 100755 --- a/subprojects/patch_open5gs.sh +++ b/subprojects/patch_open5gs.sh @@ -18,9 +18,11 @@ patch_cmd=`which patch` if ! grep -q '/\* rt-5gms-applicatiopn-function patch applied \*/' "$open5gs_src/lib/sbi/server.c"; then (cd "$open5gs_src"; "$patch_cmd" -p1 < Date: Mon, 20 Feb 2023 16:37:51 +0000 Subject: [PATCH 06/48] implementation of M1 Content Protocols Discovery --- meson.build | 4 +- .../ContentProtocolsDiscovery_body.json | 8 + src/5gmsaf/context.h | 7 + src/5gmsaf/meson.build | 31 +++ src/5gmsaf/msaf-sm.c | 214 +++++++++++------- src/5gmsaf/server.c | 66 ++++-- src/5gmsaf/server.h | 2 +- 7 files changed, 226 insertions(+), 106 deletions(-) create mode 100644 src/5gmsaf/ContentProtocolsDiscovery_body.json diff --git a/meson.build b/meson.build index cf8744e..6ea7cbf 100644 --- a/meson.build +++ b/meson.build @@ -9,13 +9,13 @@ project('rt-5gms-application-function', 'c', version : '1.2.0', license : '5G-MAG Public', - meson_version : '>= 0.47.0', + meson_version : '>= 0.59.0', default_options : [ 'c_std=gnu89', ], ) -fiveg_api_release = '17' +fiveg_api_release = '17.3.0' sh_cmd = find_program('sh') patch_open5gs_result = run_command([sh_cmd, '-c', '"$MESON_SOURCE_ROOT/subprojects/patch_open5gs.sh" open5gs'], check: true, capture: false) diff --git a/src/5gmsaf/ContentProtocolsDiscovery_body.json b/src/5gmsaf/ContentProtocolsDiscovery_body.json new file mode 100644 index 0000000..824bb6c --- /dev/null +++ b/src/5gmsaf/ContentProtocolsDiscovery_body.json @@ -0,0 +1,8 @@ +{ + "downlinkIngestProtocols": [ + { + "termIdentifier": "urn:3gpp:5gms:content-protocol:http-pull-ingest", + "descriptionLocator": "https://www.etsi.org/deliver/etsi_ts/126500_126599/126512/17.03.00_60/ts_126512v170300p.pdf#page=67" + } + ] +} diff --git a/src/5gmsaf/context.h b/src/5gmsaf/context.h index 1920759..e73a922 100644 --- a/src/5gmsaf/context.h +++ b/src/5gmsaf/context.h @@ -23,6 +23,13 @@ program. If this file is missing then the license can be retrieved from #include #include +#include "openapi/api/TS26512_M1_ProvisioningSessionsAPI-info.h" +#include "openapi/api/TS26512_M1_ServerCertificatesProvisioningAPI-info.h" +#include "openapi/api/TS26512_M1_ContentHostingProvisioningAPI-info.h" +#include "openapi/api/M3_ServerCertificatesProvisioningAPI-info.h" +#include "openapi/api/M3_ContentHostingProvisioningAPI-info.h" +#include "openapi/api/TS26512_M5_ServiceAccessInformationAPI-info.h" +#include "openapi/api/TS26512_M1_ContentProtocolsDiscoveryAPI-info.h" #include "openapi/model/content_hosting_configuration.h" #include "openapi/model/service_access_information_resource.h" #include "provisioning-session.h" diff --git a/src/5gmsaf/meson.build b/src/5gmsaf/meson.build index 531904d..6137c96 100644 --- a/src/5gmsaf/meson.build +++ b/src/5gmsaf/meson.build @@ -17,11 +17,23 @@ python3_exe = open5gs_project.get_variable('python3_exe') mkdir_p = open5gs_project.get_variable('mkdir_p') install_conf = open5gs_project.get_variable('install_conf') +fs = import('fs') + +fiveg_api_release = '17.3.0' + libmsaf_dist_sources = files(''' context.c context.h event.c event.h + server.h + server.c + certmgr.c + certmgr.h + hash.h + hash.c + response-cache-control.h + response-cache-control.c provisioning-session.h provisioning-session.c application-server-context.h @@ -174,7 +186,26 @@ libmsaf_gen_sources = ''' gen_5gmsaf_openapi = find_program('sh') openapi_gen_result = run_command([gen_5gmsaf_openapi,'-c','$MESON_SOURCE_ROOT/$MESON_SUBDIR/generator-5gmsaf', '-b', 'REL-'+fiveg_api_release], check: true, capture: false) +json_file = files(['ContentProtocolsDiscovery_body.json']) +file_content = '' +data = fs.read(json_file).split('\n') + +foreach line : data + file_content = file_content + ''.join(line + '\\n') +endforeach + +file_hash = fs.hash(json_file, 'sha256') +json_file_time = run_command(['stat', '-c', '%Y', json_file]) +file_time = json_file_time.stdout().strip() + +content_hosting_discovery_protocols_conf = configuration_data() +content_hosting_discovery_protocols_conf.set_quoted('CONTENT_PROTOCOLS_DISCOVERY_JSON', file_content) +content_hosting_discovery_protocols_conf.set_quoted('CONTENT_PROTOCOLS_DISCOVERY_JSON_HASH', file_hash) +content_hosting_discovery_protocols_conf.set('CONTENT_PROTOCOLS_DISCOVERY_JSON_TIME', file_time) +configure_file(output : 'ContentProtocolsDiscovery_body.h', configuration : content_hosting_discovery_protocols_conf) + version_conf = configuration_data() +version_conf.set_quoted('MSAF_NAME', meson.project_name()) version_conf.set_quoted('MSAF_VERSION', meson.project_version()) version_conf.set_quoted('FIVEG_API_RELEASE', fiveg_api_release) configure_file(output : 'msaf-version.h', configuration : version_conf) diff --git a/src/5gmsaf/msaf-sm.c b/src/5gmsaf/msaf-sm.c index 8f32e8d..225384c 100644 --- a/src/5gmsaf/msaf-sm.c +++ b/src/5gmsaf/msaf-sm.c @@ -67,7 +67,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) rv = ogs_sbi_parse_header(&message, &request->h); if (rv != OGS_OK) { ogs_error("ogs_sbi_parse_header() failed"); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "cannot parse HTTP message", NULL, NULL)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "cannot parse HTTP message", NULL, NULL, NULL)); break; } @@ -117,7 +117,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) error = ogs_msprintf("Version [%s] not supported", message.h.api.version); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL)); ogs_sbi_message_free(&message); ogs_free(error); @@ -145,7 +145,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); - ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL, "m1 contentHostingConfiguration")); ogs_sbi_message_free(&message); return; @@ -188,7 +188,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Provisioning Session [%s] is not assigned to an Application Server", message.h.resource.component[1]); char *err = NULL; asprintf(&err,"Provisioning Session [%s] is not assigned to an Application Server", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session is not assigned to an Application Server.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session is not assigned to an Application Server.", err, NULL, "m1 contentHostingConfiguration")); } } @@ -196,7 +196,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Provisioning Session [%s]: Unable to get information about Application Server", message.h.resource.component[1]); char *err = NULL; asprintf(&err,"Provisioning Session [%s] : Unable to get information about Application Server", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Unable to get information about Application Server", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Unable to get information about Application Server", err, NULL, "m1 contentHostingConfiguration")); } next_action_for_application_server(as_state); @@ -212,7 +212,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; asprintf(&err,"Provisioning session [%s] does not exist.", message.h.resource.component[1]); ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, "m1 contentHostingConfiguration")); } @@ -238,7 +238,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"While creating the Content Hosting Configuration for the Provisioning Session [%s], entryPointPath does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring ); ogs_error("While creating the Content Hosting Configuration for the Provisioning Session [%s], entryPointPath does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring); - ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL, "m1 contentHostingConfiguration")); cJSON_Delete(content_hosting_config); break; @@ -280,7 +280,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; ogs_error("Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); asprintf(&err,"Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL, "m1 contentHostingConfiguration")); } @@ -290,7 +290,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Failed to populate Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); asprintf(&err,"Creation of the Content Hosting Configuration failed for the Provisioning Session [%s]", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 500, 2, &message, "Creation of the Content Hosting Configuration failed.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 500, 2, &message, "Creation of the Content Hosting Configuration failed.", err, NULL, "m1 contentHostingConfiguration")); } @@ -299,7 +299,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"Provisioning session [%s]does not exist.", message.h.resource.component[1]); ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, "m1 contentHostingConfiguration")); } @@ -327,15 +327,20 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) if (csr) { msaf_certificate_t *csr_cert; - char *location; + char *location; + int m1_server_certificates_response_max_age; csr_cert = server_cert_new("newcsr", NULL); ogs_sbi_response_t *response; location = ogs_msprintf("%s/%s", request->h.uri, csr_cert->id); - response = nf_server_new_response(location, "application/x-pem-file", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, "m1 contentHostingConfiguration"); + if(csr_cert->cache_control_max_age){ + m1_server_certificates_response_max_age = csr_cert->cache_control_max_age; + } else { + m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; + } + response = nf_server_new_response(location, "application/x-pem-file", csr_cert->last_modified, csr_cert->server_certificate_hash, m1_server_certificates_response_max_age, "m1 certificates"); - response->http.content_length = strlen(csr_cert->certificate); - response->http.content = ogs_strdup(csr_cert->certificate); - response->status = 200; + nf_server_populate_response(response, strlen(csr_cert->certificate), ogs_strdup(csr_cert->certificate), 200); + ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); ogs_free(location); @@ -355,23 +360,27 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) cert = check_in_cert_list(canonical_domain_name); if (cert != NULL) { ogs_sbi_response_t *response; - char *location; - response = ogs_sbi_response_new(); - response->status = 200; + char *location; location = ogs_msprintf("%s/%s", request->h.uri, cert); - ogs_sbi_header_set(response->http.headers, "Location", location); + response = nf_server_new_response(location, NULL, NULL, NULL, NULL, "m1 certificates"); + nf_server_populate_response(response, NULL, NULL, 200); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); ogs_free(location); } else { msaf_certificate_t *new_cert; + int m1_server_certificates_response_max_age; new_cert = server_cert_new("newcert", NULL); ogs_sbi_response_t *response; - char *location; - response = ogs_sbi_response_new(); - response->status = 200; + char *location; location = ogs_msprintf("%s/%s", request->h.uri, new_cert->id); - ogs_sbi_header_set(response->http.headers, "Location", location); + if(new_cert->cache_control_max_age){ + m1_server_certificates_response_max_age = new_cert->cache_control_max_age; + } else { + m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; + } + response = nf_server_new_response(location, NULL, new_cert->last_modified, new_cert->server_certificate_hash, m1_server_certificates_response_max_age, "m1 certificates"); + nf_server_populate_response(response, NULL, NULL, 200); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); ogs_free(location); @@ -385,7 +394,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"Provisioning session [%s] does not exists.", message.h.resource.component[1]); ogs_error("Provisioning session [%s] does not exists.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL, "m1 certificates")); } @@ -435,7 +444,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; asprintf(&err,"Creation of the Provisioning session failed."); ogs_error("Creation of the Provisioning session failed."); - ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Creation of the Provisioning session failed.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Creation of the Provisioning session failed.", err, NULL, "m1 provisioningSession")); } } @@ -455,28 +464,35 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) if(!cert) { ogs_error("unable to retrieve certificate [%s]", message.h.resource.component[3]); + char *err = NULL; + asprintf(&err,"Unable to retrieve Certificate not yet available"); + ogs_error("Unable to retrieve certificate .", cert->id); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate not yet available.", err, NULL, "m1 certificates")); return; } - - response = ogs_sbi_response_new(); + if(!cert->return_code) { - response->http.content_length = strlen(cert->certificate); - response->http.content = ogs_strdup(cert->certificate); - response->status = 200; - ogs_sbi_header_set(response->http.headers, "Content-Type", "application/x-pem-file"); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + int m1_server_certificates_response_max_age; + if(cert->cache_control_max_age){ + m1_server_certificates_response_max_age = cert->cache_control_max_age; + } else { + m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; + } + response = nf_server_new_response(NULL, "application/x-pem-file", cert->last_modified, cert->server_certificate_hash, m1_server_certificates_response_max_age, "m1 certificates"); + nf_server_populate_response(response, strlen(cert->certificate), ogs_strdup(cert->certificate), 200); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); } else if(cert->return_code == 4){ char *err = NULL; asprintf(&err,"Certificate [%s] does not exists.", cert->id); ogs_error("Certificate [%s] does not exists.", cert->id); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exists.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exists.", err, NULL, "m1 certificates")); } else if(cert->return_code == 8){ char *err = NULL; asprintf(&err,"Certificate [%s] not yet available.", cert->id); ogs_error("Certificate [%s] not yet available.", cert->id); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate not yet available.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate not yet available.", err, NULL, "m1 certificates")); @@ -484,7 +500,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; asprintf(&err,"Certificate [%s] management problem.", cert->id); ogs_error("Certificate [%s] management problem.", cert->id); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, "m1 certificates")); } @@ -495,7 +511,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; asprintf(&err,"Provisioning session [%s] is not available.", message.h.resource.component[1]); ogs_error("Provisioning session [%s] is not available.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exists.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exists.", err, NULL, "m1 certificates")); } @@ -504,8 +520,8 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) else if (message.h.resource.component[1] && message.h.resource.component[2]) { msaf_provisioning_session_t *msaf_provisioning_session; + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); if(msaf_provisioning_session) { cJSON *chc; chc = msaf_get_content_hosting_configuration_by_provisioning_session_id(message.h.resource.component[1]); @@ -525,7 +541,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Provisioning Session [%s]: Unable to retrieve the Content Hosting Configuration", message.h.resource.component[1]); asprintf(&err,"Provisioning Session [%s]: Unable to retrieve the Content Hosting Configuration", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL, "m1 contentHostingConfiguration")); @@ -536,12 +552,25 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, "m1 contentHostingConfiguration")); } - } - + } else if (!strcmp(message.h.resource.component[2],"protocols")) { + if(msaf_provisioning_session) { + ogs_sbi_response_t *response; + ogs_info("CONTENT_PROTOCOLS_DISCOVERY_JSON: %s", CONTENT_PROTOCOLS_DISCOVERY_JSON); + response = nf_server_new_response(NULL, "application/json", CONTENT_PROTOCOLS_DISCOVERY_JSON_TIME, CONTENT_PROTOCOLS_DISCOVERY_JSON_HASH, msaf_self()->config.server_response_cache_control->m1_content_protocols_response_max_age, "m1 contentProtocolsDiscovery"); + ogs_assert(response); + nf_server_populate_response(response, strlen(CONTENT_PROTOCOLS_DISCOVERY_JSON), ogs_strdup(CONTENT_PROTOCOLS_DISCOVERY_JSON), 200); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, "m1 contentProtocolsDiscovery")); + } + } } else if (message.h.resource.component[1]) { msaf_provisioning_session_t *msaf_provisioning_session = NULL; cJSON *provisioning_session = NULL; @@ -567,7 +596,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"Provisioning Session [%s] is not available.", message.h.resource.component[1]); ogs_error("Provisioning Session [%s] is not available.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL, "m1 contentHostingConfiguration")); } } break; @@ -596,7 +625,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"While updating the Content Hosting Configuration for the Provisioning Session [%s], Entry Point Path does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring ); ogs_error("While updating the Content Hosting Configuration for the provisioning Session [%s], Entry Point Path does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring); - ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL, "m1 contentHostingConfiguration")); cJSON_Delete(content_hosting_config); break; @@ -639,7 +668,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"Provisioning Session [%s]: Update to Content Hosting Configuration failed.", message.h.resource.component[1]); ogs_error("Update of the Content Hosting Configuration failed."); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Failed to update the contentHostingConfiguration.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Failed to update the contentHostingConfiguration.", err, NULL, "m1 contentHostingConfiguration")); } } @@ -662,7 +691,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Unsupported Media Type: received type: %s, should have been application/x-pem-file", type); asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-pem-file", type); - ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL, "m1 certificates")); ogs_sbi_message_free(&message); return; @@ -679,10 +708,9 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) rv = server_cert_set(cert_id, cert); // response = ogs_sbi_response_new(); - if (rv == 0){ - - response = ogs_sbi_response_new(); - response->status = 204; + if (rv == 0){ + response = nf_server_new_response(NULL, NULL, NULL, NULL, NULL, "m1 certificates"); + nf_server_populate_response(response, NULL, NULL, 204); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); } else if (rv == 3 ) { @@ -690,33 +718,33 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; ogs_error("A server certificate with id [%s] already exist", cert_id); asprintf(&err,"A server certificate with id [%s] already exist", cert_id); - ogs_assert(true == nf_server_send_error(stream, 403, 3, &message, "A server certificate already exist.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 403, 3, &message, "A server certificate already exist.", err, NULL, "m1 certificates")); } else if(rv == 4) { char *err = NULL; ogs_error("Server certificate with id [%s] does not exist", cert_id); asprintf(&err,"Server certificate with id [%s] does not exist", cert_id); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Server certificate does not exist.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Server certificate does not exist.", err, NULL, "m1 certificates")); } else if(rv == 5) { char *err = NULL; ogs_error("CSR was never generated for this certificate Id [%s]", cert_id); asprintf(&err,"CSR was never generated for this certificate Id [%s]", cert_id); - ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "CSR was never generated for the certificate.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "CSR was never generated for the certificate.", err, NULL, "m1 certificates")); } else if(rv == 6) { char *err = NULL; ogs_error("The public certificate [%s] provided does not match the key", cert_id); asprintf(&err,"The public certificate [%s] provided does not match the key", cert_id); - ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "The public certificate provided does not match the key.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "The public certificate provided does not match the key.", err, NULL, "m1 certificates")); } else { char *err = NULL; ogs_error("There was a certificate management problem for the certificate id [%s]", cert_id); asprintf(&err,"There was a certificate management problem for the certificate id [%s].", cert_id); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "There was a certificate management problem.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "There was a certificate management problem.", err, NULL, "m1 certificates")); } @@ -729,7 +757,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, "m1 certificates")); } @@ -747,9 +775,8 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) int rv; rv = server_cert_delete(message.h.resource.component[3]); if ((rv == 0) || (rv == 8)){ - - response = ogs_sbi_response_new(); - response->status = 204; + response = nf_server_new_response(NULL, NULL, NULL, NULL, NULL, "m1 certificates"); + nf_server_populate_response(response, NULL, NULL, 204); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); } else if (rv == 4 ) { @@ -757,14 +784,14 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"Certificate [%s] does not exist.", message.h.resource.component[3]); ogs_error("Certificate [%s] does not exist.", message.h.resource.component[3]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exist.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exist.", err, NULL, "m1 certificates")); } else { char *err = NULL; asprintf(&err,"Certificate management problem for certificate [%s].", message.h.resource.component[3]); ogs_error("Certificate management problem."); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, "m1 certificates")); } @@ -774,13 +801,41 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, "m1 certificates")); } - } else + } else if (message.h.resource.component[1] && message.h.resource.component[2]) { + msaf_provisioning_session_t *msaf_provisioning_session; + ogs_sbi_response_t *response; + if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if(msaf_provisioning_session){ + if(msaf_provisioning_session && msaf_provisioning_session->contentHostingConfiguration) { + msaf_delete_content_hosting_configuration(message.h.resource.component[1]); + OpenAPI_content_hosting_configuration_free(msaf_provisioning_session->contentHostingConfiguration); + msaf_provisioning_session->contentHostingConfiguration = NULL; + response = nf_server_new_response(NULL, NULL, NULL, NULL, NULL, "m1 contentHostingConfiguration"); + ogs_assert(response); + nf_server_populate_response(response, NULL, NULL, 204); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + break; + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] has no Content Hosting Configuration.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] has no Content Hosting Configuration.", message.h.resource.component[1] ); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Content Hosting Configuration does not exist.", err, NULL, "m1 contentHostingConfiguration")); + } + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] does not exists.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] does not exists.", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, "m1 contentHostingConfiguration")); + } - if (message.h.resource.component[1]) { + } + + } else if (message.h.resource.component[1]) { ogs_sbi_response_t *response; msaf_provisioning_session_t *provisioning_session = NULL; provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); @@ -790,21 +845,18 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Provisioning session [%s] either not found or already marked for deletion.",message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session either not found or already marked for deletion..", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session either not found or already marked for deletion.", err, NULL, "m1 provisioningSession")); } else { provisioning_session->marked_for_deletion = 1; - - response = ogs_sbi_response_new(); + response = nf_server_new_response(NULL, NULL, NULL, NULL, NULL, "m1 provisioningSession"); ogs_assert(response); - response->status = 202; + nf_server_populate_response(response, NULL, NULL, 202); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - msaf_delete_content_hosting_configuration(message.h.resource.component[1]); msaf_delete_certificate(message.h.resource.component[1]); msaf_context_provisioning_session_free(provisioning_session); msaf_provisioning_session_hash_remove(message.h.resource.component[1]); - } } @@ -812,7 +864,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) DEFAULT ogs_error("Invalid HTTP method [%s]", message.h.method); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 0, &message, "Invalid HTTP method", message.h.method, NULL)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 0, &message, "Invalid HTTP method.", message.h.method, NULL, NULL)); END break; @@ -822,7 +874,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Invalid resource name [%s]", message.h.resource.component[0]); asprintf(&err,"Invalid resource name [%s]", message.h.resource.component[0]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid resource name", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid resource name", err, NULL, NULL)); END ogs_sbi_message_free(&message); @@ -835,7 +887,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) error = ogs_msprintf("Version [%s] not supported", message.h.api.version); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL)); ogs_sbi_message_free(&message); ogs_free(error); @@ -854,7 +906,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; asprintf(&err,"Provisioning Session [%s] not found.", message.h.resource.component[1]); ogs_error("Client requested invalid Provisioning Session [%s]", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Provisioning Session not found.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Provisioning Session not found.", err, NULL, "m5")); } else if (msaf_provisioning_session->serviceAccessInformation) { service_access_information = msaf_context_retrieve_service_access_information(message.h.resource.component[1]); @@ -872,7 +924,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"Service Access Information for the Provisioning Session [%s] not found.", message.h.resource.component[1]); ogs_error("Client requested invalid Service Access Information for the Provisioning Session [%s]", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL, "m5")); } @@ -881,14 +933,14 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"Provisioning Session [%s] has no Service Access Information associated with it.", message.h.resource.component[1]); ogs_error("Provisioning Session [%s] has no Service Access Information associated with it", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL, "m5")); } break; DEFAULT ogs_error("Invalid HTTP method [%s]", message.h.method); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 1, &message, "Invalid HTTP method.", message.h.method, NULL)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 1, &message, "Invalid HTTP method.", message.h.method, NULL, NULL)); END break; @@ -896,7 +948,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Invalid resource name [%s]", message.h.resource.component[0]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid resource name.", message.h.resource.component[0], NULL)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid resource name.", message.h.resource.component[0], NULL, NULL)); END ogs_sbi_message_free(&message); @@ -904,7 +956,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) DEFAULT ogs_error("Invalid API name [%s]", message.h.service.name); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid API name.", message.h.service.name, NULL)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid API name.", message.h.service.name, NULL, NULL)); END break; @@ -971,7 +1023,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); - ogs_assert(true == nf_server_send_error(stream, 415, 2, &message, "Provisioning session does not exist.", err, NULL)); + ogs_assert(true == nf_server_send_error(stream, 415, 2, &message, "Provisioning session does not exist.", err, NULL, "m3 contentHostingConfiguration")); ogs_sbi_message_free(&message); return; @@ -1075,7 +1127,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_assert(true == nf_server_send_error( purge_node->m1_purge_info->m1_stream, - response->status, 3, &purge_node->m1_purge_info->m1_message, "Problem occured during cache purge", error, purge_cache_err)); + response->status, 3, &purge_node->m1_purge_info->m1_message, "Problem occured during cache purge", error, purge_cache_err, "m1 contentHostingConfiguration")); ogs_list_for_each_safe(&as_state->purge_content_hosting_cache, next, content_hosting_cache){ if (purge_node->purge_regex) { diff --git a/src/5gmsaf/server.c b/src/5gmsaf/server.c index 2523a62..f81b7d2 100644 --- a/src/5gmsaf/server.c +++ b/src/5gmsaf/server.c @@ -11,13 +11,13 @@ program. If this file is missing then the license can be retrieved from #include "ogs-sbi.h" #include "server.h" #include "utilities.h" -#include "version.h" +#include "msaf-version.h" static bool nf_server_send_problem( - ogs_sbi_stream_t *stream, OpenAPI_problem_details_t *problem); + ogs_sbi_stream_t *stream, OpenAPI_problem_details_t *problem, char *interface); static ogs_sbi_response_t *nf_build_response( - ogs_sbi_message_t *message, int status); + ogs_sbi_message_t *message, int status, char *interface); static bool nf_build_content( ogs_sbi_http_message_t *http, ogs_sbi_message_t *message); @@ -65,30 +65,56 @@ ogs_sbi_response_t *nf_server_new_response(char *location, char *content_type, t if(!interface){ - server = ogs_msprintf("5GMSdAF-%s/%s %s/%s",msaf_self()->server_name, FIVE_API_RELEASE, MSAF_NAME, MSAF_VERSION); + server = ogs_msprintf("5GMSdAF-%s/%s %s/%s",msaf_self()->server_name, FIVEG_API_RELEASE, MSAF_NAME, MSAF_VERSION); } else if(!strcmp(interface, "m1 provisioningSession")) { - server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", _OpenAPI_provisioning_session_info_title, _OpenAPI_provisioning_session_info_version); - server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVE_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); + server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", M1_PROVISIONINGSESSIONS_API_NAME, M1_PROVISIONINGSESSIONS_API_VERSION); + server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVEG_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); } else if(!strcmp(interface, "m1 contentHostingConfiguration")) { - server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", _OpenAPI_content_hosting_configuration_info_title, _OpenAPI_content_hosting_configuration_info_version); - server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVE_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); + server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", M1_CONTENTHOSTINGPROVISIONING_API_NAME, M1_CONTENTHOSTINGPROVISIONING_API_VERSION); + server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVEG_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); - } else if(!strcmp(interface, "m5")) + } else if(!strcmp(interface, "m1 contentProtocolsDiscovery")) { - server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", _OpenAPI_service_access_information_resource_info_title, _OpenAPI_service_access_information_resource_info_version); - server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVE_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); + server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", M1_CONTENTPROTOCOLSDISCOVERY_API_NAME, M1_CONTENTPROTOCOLSDISCOVERY_API_VERSION); + server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVEG_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); + + } + else if(!strcmp(interface, "m1 certificates")) + { + + server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", M1_SERVERCERTIFICATESPROVISIONING_API_NAME, M1_SERVERCERTIFICATESPROVISIONING_API_VERSION); + server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVEG_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); + + } else if(!strcmp(interface, "m3 contentHostingConfiguration")) + { + + server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", M3_CONTENTHOSTINGPROVISIONING_API_NAME, M3_CONTENTHOSTINGPROVISIONING_API_VERSION); + server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVEG_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); + + } else if(!strcmp(interface, "m3 certificates")) + { + + server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", M3_SERVERCERTIFICATESPROVISIONING_API_NAME, M3_SERVERCERTIFICATESPROVISIONING_API_VERSION); + server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVEG_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); + } + + else if(!strcmp(interface, "m5")) + { + + server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", M5_SERVICEACCESSINFORMATION_API_NAME, M5_SERVICEACCESSINFORMATION_API_VERSION); + server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVEG_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); } else { - server = ogs_msprintf("5GMSdAF-%s/%s %s/%s",msaf_self()->server_name, FIVE_API_RELEASE, MSAF_NAME, MSAF_VERSION); + server = ogs_msprintf("5GMSdAF-%s/%s %s/%s",msaf_self()->server_name, FIVEG_API_RELEASE, MSAF_NAME, MSAF_VERSION); } ogs_sbi_header_set(response->http.headers, "Server", server); @@ -109,12 +135,8 @@ ogs_sbi_response_t *nf_server_populate_response(ogs_sbi_response_t *response, in } - - - - static bool nf_server_send_problem( - ogs_sbi_stream_t *stream, OpenAPI_problem_details_t *problem) + ogs_sbi_stream_t *stream, OpenAPI_problem_details_t *problem, char *interface) { ogs_sbi_message_t message; ogs_sbi_response_t *response = NULL; @@ -127,7 +149,7 @@ static bool nf_server_send_problem( message.http.content_type = (char*)"application/problem+json"; message.ProblemDetails = problem; - response = nf_build_response(&message, problem->status); + response = nf_build_response(&message, problem->status, interface); ogs_assert(response); ogs_sbi_server_send_response(stream, response); @@ -138,7 +160,7 @@ static bool nf_server_send_problem( bool nf_server_send_error(ogs_sbi_stream_t *stream, int status, int number_of_components, ogs_sbi_message_t *message, - const char *title, const char *detail, cJSON * problem_detail) + const char *title, const char *detail, cJSON * problem_detail, char *interface) { OpenAPI_problem_details_t problem; OpenAPI_problem_details_t *problem_details = NULL; @@ -177,7 +199,7 @@ bool nf_server_send_error(ogs_sbi_stream_t *stream, problem.title = (char*)title; problem.detail = (char*)detail; - nf_server_send_problem(stream, &problem); + nf_server_send_problem(stream, &problem, interface); if (problem.type) ogs_free(problem.type); @@ -190,13 +212,13 @@ bool nf_server_send_error(ogs_sbi_stream_t *stream, } ogs_sbi_response_t *nf_build_response( - ogs_sbi_message_t *message, int status) + ogs_sbi_message_t *message, int status, char *interface) { ogs_sbi_response_t *response = NULL; ogs_assert(message); - response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL); + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, interface); //response = ogs_sbi_response_new(); ogs_expect_or_return_val(response, NULL); diff --git a/src/5gmsaf/server.h b/src/5gmsaf/server.h index d9efb4c..3ccc74a 100644 --- a/src/5gmsaf/server.h +++ b/src/5gmsaf/server.h @@ -20,7 +20,7 @@ extern "C" { extern bool nf_server_send_error(ogs_sbi_stream_t *stream, int status, int number_of_components, ogs_sbi_message_t *message, - const char *title, const char *detail, cJSON * problem_detail); + const char *title, const char *detail, cJSON * problem_detail, char *interface); extern ogs_sbi_response_t *nf_server_new_response(char *location, char *content_type, time_t last_modified, char *etag, int cache_control, char *interface); extern ogs_sbi_response_t *nf_server_populate_response(ogs_sbi_response_t *response, int content_length, char *content, int status); From a3547d6df3518c2701499d3ea2ea89f043f57976 Mon Sep 17 00:00:00 2001 From: deva Date: Wed, 22 Feb 2023 10:22:21 +0000 Subject: [PATCH 07/48] M1 Content Protocols Discovery restructured --- meson.build | 4 +- src/5gmsaf/context.c | 5 +- src/5gmsaf/context.h | 7 -- src/5gmsaf/meson.build | 2 - src/5gmsaf/msaf-sm.c | 238 +++++++++++++++++++++++++++-------------- src/5gmsaf/server.c | 85 ++++----------- src/5gmsaf/server.h | 15 ++- 7 files changed, 197 insertions(+), 159 deletions(-) diff --git a/meson.build b/meson.build index 6ea7cbf..4969880 100644 --- a/meson.build +++ b/meson.build @@ -6,6 +6,8 @@ # program. If this file is missing then the license can be retrieved from # https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +# Meson module fs and its functions like fs.hash_file require atleast meson 0.59.0 + project('rt-5gms-application-function', 'c', version : '1.2.0', license : '5G-MAG Public', @@ -15,7 +17,7 @@ project('rt-5gms-application-function', 'c', ], ) -fiveg_api_release = '17.3.0' +fiveg_api_release = '17' sh_cmd = find_program('sh') patch_open5gs_result = run_command([sh_cmd, '-c', '"$MESON_SOURCE_ROOT/subprojects/patch_open5gs.sh" open5gs'], check: true, capture: false) diff --git a/src/5gmsaf/context.c b/src/5gmsaf/context.c index d0f8ccc..3f116d5 100644 --- a/src/5gmsaf/context.c +++ b/src/5gmsaf/context.c @@ -202,6 +202,7 @@ int msaf_context_parse_config(void) int m1_provisioning_session_response_max_age = SERVER_RESPONSE_MAX_AGE; int m1_content_hosting_configurations_response_max_age = SERVER_RESPONSE_MAX_AGE; + int m1_server_certificates_response_max_age = SERVER_RESPONSE_MAX_AGE; int m1_content_protocols_response_max_age = M1_CONTENT_PROTOCOLS_RESPONSE_MAX_AGE; int m5_service_access_information_response_max_age = SERVER_RESPONSE_MAX_AGE; while (ogs_yaml_iter_next(&cc_iter)) { @@ -209,6 +210,8 @@ int msaf_context_parse_config(void) ogs_assert(cc_key); if (!strcmp(cc_key, "m1ProvisioningSessions")) { m1_provisioning_session_response_max_age = ascii_to_long(ogs_yaml_iter_value(&cc_iter)); + } else if (!strcmp(cc_key, "m1ServerCertificates")) { + m1_server_certificates_response_max_age = ascii_to_long(ogs_yaml_iter_value(&cc_iter)); } else if (!strcmp(cc_key, "m1ContentHostingConfigurations")) { m1_content_hosting_configurations_response_max_age = ascii_to_long(ogs_yaml_iter_value(&cc_iter)); } else if (!strcmp(cc_key, "m1ContentProtocols")) { @@ -217,7 +220,7 @@ int msaf_context_parse_config(void) m5_service_access_information_response_max_age = ascii_to_long(ogs_yaml_iter_value(&cc_iter)); } } - msaf_server_response_cache_control_set_from_config(m1_provisioning_session_response_max_age, m1_content_hosting_configurations_response_max_age, m1_content_protocols_response_max_age, m5_service_access_information_response_max_age); + msaf_server_response_cache_control_set_from_config(m1_provisioning_session_response_max_age, m1_content_hosting_configurations_response_max_age, m1_server_certificates_response_max_age, m1_content_protocols_response_max_age, m5_service_access_information_response_max_age); } else if (!strcmp(msaf_key, "sbi")) { if(!self->config.open5gsIntegration_flag) { diff --git a/src/5gmsaf/context.h b/src/5gmsaf/context.h index e73a922..1920759 100644 --- a/src/5gmsaf/context.h +++ b/src/5gmsaf/context.h @@ -23,13 +23,6 @@ program. If this file is missing then the license can be retrieved from #include #include -#include "openapi/api/TS26512_M1_ProvisioningSessionsAPI-info.h" -#include "openapi/api/TS26512_M1_ServerCertificatesProvisioningAPI-info.h" -#include "openapi/api/TS26512_M1_ContentHostingProvisioningAPI-info.h" -#include "openapi/api/M3_ServerCertificatesProvisioningAPI-info.h" -#include "openapi/api/M3_ContentHostingProvisioningAPI-info.h" -#include "openapi/api/TS26512_M5_ServiceAccessInformationAPI-info.h" -#include "openapi/api/TS26512_M1_ContentProtocolsDiscoveryAPI-info.h" #include "openapi/model/content_hosting_configuration.h" #include "openapi/model/service_access_information_resource.h" #include "provisioning-session.h" diff --git a/src/5gmsaf/meson.build b/src/5gmsaf/meson.build index 6137c96..68f79bd 100644 --- a/src/5gmsaf/meson.build +++ b/src/5gmsaf/meson.build @@ -19,8 +19,6 @@ install_conf = open5gs_project.get_variable('install_conf') fs = import('fs') -fiveg_api_release = '17.3.0' - libmsaf_dist_sources = files(''' context.c context.h diff --git a/src/5gmsaf/msaf-sm.c b/src/5gmsaf/msaf-sm.c index 225384c..0e46356 100644 --- a/src/5gmsaf/msaf-sm.c +++ b/src/5gmsaf/msaf-sm.c @@ -15,6 +15,44 @@ #include "certmgr.h" #include "server.h" #include "response-cache-control.h" +#include "msaf-version.h" +#include "openapi/api/TS26512_M1_ProvisioningSessionsAPI-info.h" +#include "openapi/api/TS26512_M1_ServerCertificatesProvisioningAPI-info.h" +#include "openapi/api/TS26512_M1_ContentHostingProvisioningAPI-info.h" +#include "openapi/api/M3_ServerCertificatesProvisioningAPI-info.h" +#include "openapi/api/M3_ContentHostingProvisioningAPI-info.h" +#include "openapi/api/TS26512_M5_ServiceAccessInformationAPI-info.h" +#include "openapi/api/TS26512_M1_ContentProtocolsDiscoveryAPI-info.h" + +const nf_server_interface_metadata_t +m1_provisioningsession_api_metadata = { +M1_PROVISIONINGSESSIONS_API_NAME, +M1_PROVISIONINGSESSIONS_API_VERSION}; + +const nf_server_interface_metadata_t +m1_contenthostingprovisioning_api_metadata = { +M1_CONTENTHOSTINGPROVISIONING_API_NAME, +M1_CONTENTHOSTINGPROVISIONING_API_VERSION}; + +const nf_server_interface_metadata_t +m1_contentprotocolsdiscovery_api_metadata = { +M1_CONTENTPROTOCOLSDISCOVERY_API_NAME, +M1_CONTENTPROTOCOLSDISCOVERY_API_VERSION}; + +const nf_server_interface_metadata_t +m1_servercertificatesprovisioning_api_metadata = { +M1_SERVERCERTIFICATESPROVISIONING_API_NAME, +M1_SERVERCERTIFICATESPROVISIONING_API_VERSION}; + +const nf_server_interface_metadata_t +m3_contenthostingprovisioning_api_metatdata = { +M3_CONTENTHOSTINGPROVISIONING_API_NAME, +M3_CONTENTHOSTINGPROVISIONING_API_VERSION}; + +const nf_server_interface_metadata_t +m5_serviceaccessinformation_api_metadata = { +M5_SERVICEACCESSINFORMATION_API_NAME, +M5_SERVICEACCESSINFORMATION_API_VERSION}; void msaf_state_initial(ogs_fsm_t *s, msaf_event_t *e) { @@ -47,12 +85,23 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) msaf_sm_debug(e); + msaf_context_server_name_set(); + char *nf_name = ogs_msprintf("5GMSdAF-%s", msaf_self()->server_name); + const nf_server_app_metadata_t app_metadata = { MSAF_NAME, MSAF_VERSION, nf_name}; + const nf_server_interface_metadata_t *m1_provisioningsession_api = &m1_provisioningsession_api_metadata; + const nf_server_interface_metadata_t *m1_contenthostingprovisioning_api = &m1_contenthostingprovisioning_api_metadata; + const nf_server_interface_metadata_t *m1_contentprotocolsdiscovery_api = &m1_contentprotocolsdiscovery_api_metadata; + const nf_server_interface_metadata_t *m1_servercertificatesprovisioning_api = &m1_servercertificatesprovisioning_api_metadata; + const nf_server_interface_metadata_t *m3_contenthostingprovisioning_api = &m3_contenthostingprovisioning_api_metatdata; + const nf_server_interface_metadata_t *m3_servercertificatesprovisioning_api = &m3_servercertificatesprovisioning_api_metadata; + const nf_server_interface_metadata_t *m5_serviceaccessinformation_api = &m5_serviceaccessinformation_api_metadata; + const nf_server_app_metadata_t *app_meta = &app_metadata; + ogs_assert(s); switch (e->h.id) { case OGS_FSM_ENTRY_SIG: - ogs_info("[%s] MSAF Running", ogs_sbi_self()->nf_instance->id); - msaf_context_server_name_set(); + ogs_info("[%s] MSAF Running", ogs_sbi_self()->nf_instance->id); break; case OGS_FSM_EXIT_SIG: @@ -67,7 +116,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) rv = ogs_sbi_parse_header(&message, &request->h); if (rv != OGS_OK) { ogs_error("ogs_sbi_parse_header() failed"); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "cannot parse HTTP message", NULL, NULL, NULL)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "cannot parse HTTP message", NULL, NULL, NULL, app_meta)); break; } @@ -117,7 +166,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) error = ogs_msprintf("Version [%s] not supported", message.h.api.version); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL, app_meta)); ogs_sbi_message_free(&message); ogs_free(error); @@ -145,7 +194,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); - ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL, "m1 contentHostingConfiguration")); + ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); ogs_sbi_message_free(&message); return; @@ -188,7 +237,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Provisioning Session [%s] is not assigned to an Application Server", message.h.resource.component[1]); char *err = NULL; asprintf(&err,"Provisioning Session [%s] is not assigned to an Application Server", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session is not assigned to an Application Server.", err, NULL, "m1 contentHostingConfiguration")); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session is not assigned to an Application Server.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } } @@ -196,7 +245,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Provisioning Session [%s]: Unable to get information about Application Server", message.h.resource.component[1]); char *err = NULL; asprintf(&err,"Provisioning Session [%s] : Unable to get information about Application Server", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Unable to get information about Application Server", err, NULL, "m1 contentHostingConfiguration")); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Unable to get information about Application Server", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } next_action_for_application_server(as_state); @@ -212,7 +261,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; asprintf(&err,"Provisioning session [%s] does not exist.", message.h.resource.component[1]); ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, "m1 contentHostingConfiguration")); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } @@ -238,7 +287,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"While creating the Content Hosting Configuration for the Provisioning Session [%s], entryPointPath does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring ); ogs_error("While creating the Content Hosting Configuration for the Provisioning Session [%s], entryPointPath does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring); - ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL, "m1 contentHostingConfiguration")); + ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); cJSON_Delete(content_hosting_config); break; @@ -269,7 +318,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) if (chc != NULL) { char *text; msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, "m1 contentHostingConfiguration"); + response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, m1_contentprotocolsdiscovery_api, app_meta); text = cJSON_Print(chc); nf_server_populate_response(response, strlen(text), text, 201); ogs_assert(response); @@ -280,7 +329,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; ogs_error("Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); asprintf(&err,"Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL, "m1 contentHostingConfiguration")); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } @@ -290,7 +339,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Failed to populate Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); asprintf(&err,"Creation of the Content Hosting Configuration failed for the Provisioning Session [%s]", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 500, 2, &message, "Creation of the Content Hosting Configuration failed.", err, NULL, "m1 contentHostingConfiguration")); + ogs_assert(true == nf_server_send_error(stream, 500, 2, &message, "Creation of the Content Hosting Configuration failed.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } @@ -299,7 +348,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"Provisioning session [%s]does not exist.", message.h.resource.component[1]); ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, "m1 contentHostingConfiguration")); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } @@ -337,7 +386,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; } - response = nf_server_new_response(location, "application/x-pem-file", csr_cert->last_modified, csr_cert->server_certificate_hash, m1_server_certificates_response_max_age, "m1 certificates"); + response = nf_server_new_response(location, "application/x-pem-file", csr_cert->last_modified, csr_cert->server_certificate_hash, m1_server_certificates_response_max_age, m1_servercertificatesprovisioning_api, app_meta); nf_server_populate_response(response, strlen(csr_cert->certificate), ogs_strdup(csr_cert->certificate), 200); @@ -362,8 +411,8 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_sbi_response_t *response; char *location; location = ogs_msprintf("%s/%s", request->h.uri, cert); - response = nf_server_new_response(location, NULL, NULL, NULL, NULL, "m1 certificates"); - nf_server_populate_response(response, NULL, NULL, 200); + response = nf_server_new_response(location, NULL, 0, NULL, 0, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 200); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); ogs_free(location); @@ -379,8 +428,8 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; } - response = nf_server_new_response(location, NULL, new_cert->last_modified, new_cert->server_certificate_hash, m1_server_certificates_response_max_age, "m1 certificates"); - nf_server_populate_response(response, NULL, NULL, 200); + response = nf_server_new_response(location, NULL, new_cert->last_modified, new_cert->server_certificate_hash, m1_server_certificates_response_max_age, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 200); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); ogs_free(location); @@ -394,7 +443,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"Provisioning session [%s] does not exists.", message.h.resource.component[1]); ogs_error("Provisioning session [%s] does not exists.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL, "m1 certificates")); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } @@ -432,7 +481,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { location = ogs_msprintf("%s%s", request->h.uri,msaf_provisioning_session->provisioningSessionId); } - response = nf_server_new_response(location, "application/json", msaf_provisioning_session->provisioningSessionReceived, msaf_provisioning_session->provisioningSessionHash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, "m1 provisioningSession"); + response = nf_server_new_response(location, "application/json", msaf_provisioning_session->provisioningSessionReceived, msaf_provisioning_session->provisioningSessionHash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, m1_provisioningsession_api, app_meta); nf_server_populate_response(response, strlen(text), text, 201); ogs_assert(response); @@ -444,7 +493,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; asprintf(&err,"Creation of the Provisioning session failed."); ogs_error("Creation of the Provisioning session failed."); - ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Creation of the Provisioning session failed.", err, NULL, "m1 provisioningSession")); + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); } } @@ -466,8 +515,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("unable to retrieve certificate [%s]", message.h.resource.component[3]); char *err = NULL; asprintf(&err,"Unable to retrieve Certificate not yet available"); - ogs_error("Unable to retrieve certificate .", cert->id); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate not yet available.", err, NULL, "m1 certificates")); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate not yet available.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); return; } @@ -478,7 +526,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; } - response = nf_server_new_response(NULL, "application/x-pem-file", cert->last_modified, cert->server_certificate_hash, m1_server_certificates_response_max_age, "m1 certificates"); + response = nf_server_new_response(NULL, "application/x-pem-file", cert->last_modified, cert->server_certificate_hash, m1_server_certificates_response_max_age, m1_servercertificatesprovisioning_api, app_meta); nf_server_populate_response(response, strlen(cert->certificate), ogs_strdup(cert->certificate), 200); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); @@ -486,13 +534,13 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; asprintf(&err,"Certificate [%s] does not exists.", cert->id); ogs_error("Certificate [%s] does not exists.", cert->id); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exists.", err, NULL, "m1 certificates")); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } else if(cert->return_code == 8){ char *err = NULL; asprintf(&err,"Certificate [%s] not yet available.", cert->id); ogs_error("Certificate [%s] not yet available.", cert->id); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate not yet available.", err, NULL, "m1 certificates")); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate not yet available.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); @@ -500,7 +548,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; asprintf(&err,"Certificate [%s] management problem.", cert->id); ogs_error("Certificate [%s] management problem.", cert->id); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, "m1 certificates")); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } @@ -511,7 +559,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; asprintf(&err,"Provisioning session [%s] is not available.", message.h.resource.component[1]); ogs_error("Provisioning session [%s] is not available.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exists.", err, NULL, "m1 certificates")); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } @@ -530,7 +578,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *text; text = cJSON_Print(chc); - response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, "m1 contentHostingConfiguration"); + response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, m1_contenthostingprovisioning_api, app_meta); ogs_assert(response); nf_server_populate_response(response, strlen(text), text, 200); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); @@ -541,7 +589,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Provisioning Session [%s]: Unable to retrieve the Content Hosting Configuration", message.h.resource.component[1]); asprintf(&err,"Provisioning Session [%s]: Unable to retrieve the Content Hosting Configuration", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL, "m1 contentHostingConfiguration")); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); @@ -552,7 +600,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, "m1 contentHostingConfiguration")); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } @@ -560,7 +608,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) if(msaf_provisioning_session) { ogs_sbi_response_t *response; ogs_info("CONTENT_PROTOCOLS_DISCOVERY_JSON: %s", CONTENT_PROTOCOLS_DISCOVERY_JSON); - response = nf_server_new_response(NULL, "application/json", CONTENT_PROTOCOLS_DISCOVERY_JSON_TIME, CONTENT_PROTOCOLS_DISCOVERY_JSON_HASH, msaf_self()->config.server_response_cache_control->m1_content_protocols_response_max_age, "m1 contentProtocolsDiscovery"); + response = nf_server_new_response(NULL, "application/json", CONTENT_PROTOCOLS_DISCOVERY_JSON_TIME, CONTENT_PROTOCOLS_DISCOVERY_JSON_HASH, msaf_self()->config.server_response_cache_control->m1_content_protocols_response_max_age, m1_contentprotocolsdiscovery_api, app_meta); ogs_assert(response); nf_server_populate_response(response, strlen(CONTENT_PROTOCOLS_DISCOVERY_JSON), ogs_strdup(CONTENT_PROTOCOLS_DISCOVERY_JSON), 200); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); @@ -568,7 +616,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, "m1 contentProtocolsDiscovery")); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contentprotocolsdiscovery_api, app_meta)); } } } else if (message.h.resource.component[1]) { @@ -584,7 +632,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *text; text = cJSON_Print(provisioning_session); - response = nf_server_new_response(NULL, "application/json", msaf_provisioning_session->provisioningSessionReceived, msaf_provisioning_session->provisioningSessionHash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, "m1 provisioningSession"); + response = nf_server_new_response(NULL, "application/json", msaf_provisioning_session->provisioningSessionReceived, msaf_provisioning_session->provisioningSessionHash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, m1_provisioningsession_api, app_meta); nf_server_populate_response(response, strlen(text), text, 200); ogs_assert(response); @@ -596,7 +644,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"Provisioning Session [%s] is not available.", message.h.resource.component[1]); ogs_error("Provisioning Session [%s] is not available.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL, "m1 contentHostingConfiguration")); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL, m1_provisioningsession_api, app_meta)); } } break; @@ -625,7 +673,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"While updating the Content Hosting Configuration for the Provisioning Session [%s], Entry Point Path does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring ); ogs_error("While updating the Content Hosting Configuration for the provisioning Session [%s], Entry Point Path does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring); - ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL, "m1 contentHostingConfiguration")); + ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); cJSON_Delete(content_hosting_config); break; @@ -668,7 +716,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"Provisioning Session [%s]: Update to Content Hosting Configuration failed.", message.h.resource.component[1]); ogs_error("Update of the Content Hosting Configuration failed."); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Failed to update the contentHostingConfiguration.", err, NULL, "m1 contentHostingConfiguration")); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Failed to update the contentHostingConfiguration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } } @@ -691,7 +739,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Unsupported Media Type: received type: %s, should have been application/x-pem-file", type); asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-pem-file", type); - ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL, "m1 certificates")); + ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); ogs_sbi_message_free(&message); return; @@ -709,8 +757,8 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) // response = ogs_sbi_response_new(); if (rv == 0){ - response = nf_server_new_response(NULL, NULL, NULL, NULL, NULL, "m1 certificates"); - nf_server_populate_response(response, NULL, NULL, 204); + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); } else if (rv == 3 ) { @@ -718,33 +766,33 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; ogs_error("A server certificate with id [%s] already exist", cert_id); asprintf(&err,"A server certificate with id [%s] already exist", cert_id); - ogs_assert(true == nf_server_send_error(stream, 403, 3, &message, "A server certificate already exist.", err, NULL, "m1 certificates")); + ogs_assert(true == nf_server_send_error(stream, 403, 3, &message, "A server certificate already exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } else if(rv == 4) { char *err = NULL; ogs_error("Server certificate with id [%s] does not exist", cert_id); asprintf(&err,"Server certificate with id [%s] does not exist", cert_id); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Server certificate does not exist.", err, NULL, "m1 certificates")); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Server certificate does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } else if(rv == 5) { char *err = NULL; ogs_error("CSR was never generated for this certificate Id [%s]", cert_id); asprintf(&err,"CSR was never generated for this certificate Id [%s]", cert_id); - ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "CSR was never generated for the certificate.", err, NULL, "m1 certificates")); + ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "CSR was never generated for the certificate.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } else if(rv == 6) { char *err = NULL; ogs_error("The public certificate [%s] provided does not match the key", cert_id); asprintf(&err,"The public certificate [%s] provided does not match the key", cert_id); - ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "The public certificate provided does not match the key.", err, NULL, "m1 certificates")); + ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "The public certificate provided does not match the key.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } else { char *err = NULL; ogs_error("There was a certificate management problem for the certificate id [%s]", cert_id); asprintf(&err,"There was a certificate management problem for the certificate id [%s].", cert_id); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "There was a certificate management problem.", err, NULL, "m1 certificates")); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "There was a certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } @@ -757,7 +805,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, "m1 certificates")); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } @@ -775,8 +823,8 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) int rv; rv = server_cert_delete(message.h.resource.component[3]); if ((rv == 0) || (rv == 8)){ - response = nf_server_new_response(NULL, NULL, NULL, NULL, NULL, "m1 certificates"); - nf_server_populate_response(response, NULL, NULL, 204); + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); } else if (rv == 4 ) { @@ -784,14 +832,14 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"Certificate [%s] does not exist.", message.h.resource.component[3]); ogs_error("Certificate [%s] does not exist.", message.h.resource.component[3]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exist.", err, NULL, "m1 certificates")); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } else { char *err = NULL; asprintf(&err,"Certificate management problem for certificate [%s].", message.h.resource.component[3]); ogs_error("Certificate management problem."); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, "m1 certificates")); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } @@ -801,7 +849,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, "m1 certificates")); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } @@ -815,22 +863,22 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) msaf_delete_content_hosting_configuration(message.h.resource.component[1]); OpenAPI_content_hosting_configuration_free(msaf_provisioning_session->contentHostingConfiguration); msaf_provisioning_session->contentHostingConfiguration = NULL; - response = nf_server_new_response(NULL, NULL, NULL, NULL, NULL, "m1 contentHostingConfiguration"); + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, m1_contenthostingprovisioning_api, app_meta); ogs_assert(response); - nf_server_populate_response(response, NULL, NULL, 204); + nf_server_populate_response(response, 0, NULL, 204); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); break; } else { char *err = NULL; asprintf(&err,"Provisioning Session [%s] has no Content Hosting Configuration.", message.h.resource.component[1]); ogs_error("Provisioning Session [%s] has no Content Hosting Configuration.", message.h.resource.component[1] ); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Content Hosting Configuration does not exist.", err, NULL, "m1 contentHostingConfiguration")); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Content Hosting Configuration does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } } else { char *err = NULL; asprintf(&err,"Provisioning Session [%s] does not exists.", message.h.resource.component[1]); ogs_error("Provisioning Session [%s] does not exists.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, "m1 contentHostingConfiguration")); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } } @@ -845,13 +893,13 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Provisioning session [%s] either not found or already marked for deletion.",message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session either not found or already marked for deletion.", err, NULL, "m1 provisioningSession")); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session either not found or already marked for deletion.", err, NULL, m1_provisioningsession_api, app_meta)); } else { provisioning_session->marked_for_deletion = 1; - response = nf_server_new_response(NULL, NULL, NULL, NULL, NULL, "m1 provisioningSession"); + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, m1_provisioningsession_api, app_meta); ogs_assert(response); - nf_server_populate_response(response, NULL, NULL, 202); + nf_server_populate_response(response, 0, NULL, 202); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); msaf_delete_content_hosting_configuration(message.h.resource.component[1]); msaf_delete_certificate(message.h.resource.component[1]); @@ -861,10 +909,33 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } break; + CASE(OGS_SBI_HTTP_METHOD_OPTIONS) + if (message.h.resource.component[1] && !strcmp(message.h.resource.component[2],"certificates") && message.h.resource.component[3]) { + ogs_sbi_response_t *response; + msaf_provisioning_session_t *provisioning_session = NULL; + provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if (provisioning_session) { + response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + + + } else { + char *err = NULL; + asprintf(&err,"Method [%s] - [%s]:[%s] - Provisioning Session [%s] does not exist.", message.h.method, message.h.resource.component[2], message.h.resource.component[3], message.h.resource.component[1]); + ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + + + } + } + break; DEFAULT ogs_error("Invalid HTTP method [%s]", message.h.method); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 0, &message, "Invalid HTTP method.", message.h.method, NULL, NULL)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 0, &message, "Invalid HTTP method.", message.h.method, NULL, NULL, app_meta)); END break; @@ -874,7 +945,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Invalid resource name [%s]", message.h.resource.component[0]); asprintf(&err,"Invalid resource name [%s]", message.h.resource.component[0]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid resource name", err, NULL, NULL)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid resource name", err, NULL, NULL, app_meta)); END ogs_sbi_message_free(&message); @@ -887,7 +958,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) error = ogs_msprintf("Version [%s] not supported", message.h.api.version); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL, app_meta)); ogs_sbi_message_free(&message); ogs_free(error); @@ -906,7 +977,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; asprintf(&err,"Provisioning Session [%s] not found.", message.h.resource.component[1]); ogs_error("Client requested invalid Provisioning Session [%s]", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Provisioning Session not found.", err, NULL, "m5")); + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Provisioning Session not found.", err, NULL, m5_serviceaccessinformation_api, app_meta)); } else if (msaf_provisioning_session->serviceAccessInformation) { service_access_information = msaf_context_retrieve_service_access_information(message.h.resource.component[1]); @@ -914,7 +985,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_sbi_response_t *response; char *text; text = cJSON_Print(service_access_information); - response = nf_server_new_response(NULL, "application/json", msaf_provisioning_session->serviceAccessInformationCreated, msaf_provisioning_session->serviceAccessInformationHash, msaf_self()->config.server_response_cache_control->m5_service_access_information_response_max_age, "m5"); + response = nf_server_new_response(NULL, "application/json", msaf_provisioning_session->serviceAccessInformationCreated, msaf_provisioning_session->serviceAccessInformationHash, msaf_self()->config.server_response_cache_control->m5_service_access_information_response_max_age, m5_serviceaccessinformation_api, app_meta); nf_server_populate_response(response, strlen(text), text, 201); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); @@ -924,7 +995,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"Service Access Information for the Provisioning Session [%s] not found.", message.h.resource.component[1]); ogs_error("Client requested invalid Service Access Information for the Provisioning Session [%s]", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL, "m5")); + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL, m5_serviceaccessinformation_api, app_meta)); } @@ -933,30 +1004,28 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) asprintf(&err,"Provisioning Session [%s] has no Service Access Information associated with it.", message.h.resource.component[1]); ogs_error("Provisioning Session [%s] has no Service Access Information associated with it", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL, "m5")); + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL, m5_serviceaccessinformation_api, app_meta)); } break; DEFAULT ogs_error("Invalid HTTP method [%s]", message.h.method); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 1, &message, "Invalid HTTP method.", message.h.method, NULL, NULL)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 1, &message, "Invalid HTTP method.", message.h.method, NULL, NULL, app_meta)); END break; DEFAULT ogs_error("Invalid resource name [%s]", - message.h.resource.component[0]); - - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid resource name.", message.h.resource.component[0], NULL, NULL)); + message.h.resource.component[0]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid resource name.", message.h.resource.component[0], NULL, NULL, app_meta)); END ogs_sbi_message_free(&message); break; DEFAULT - ogs_error("Invalid API name [%s]", message.h.service.name); - - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid API name.", message.h.service.name, NULL, NULL)); + ogs_error("Invalid API name [%s]", message.h.service.name); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid API name.", message.h.service.name, NULL, NULL, app_meta)); END break; @@ -1023,7 +1092,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); - ogs_assert(true == nf_server_send_error(stream, 415, 2, &message, "Provisioning session does not exist.", err, NULL, "m3 contentHostingConfiguration")); + ogs_assert(true == nf_server_send_error(stream, 415, 2, &message, "Provisioning session does not exist.", err, NULL, m3_contenthostingprovisioning_api, app_meta)); ogs_sbi_message_free(&message); return; @@ -1127,7 +1196,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_assert(true == nf_server_send_error( purge_node->m1_purge_info->m1_stream, - response->status, 3, &purge_node->m1_purge_info->m1_message, "Problem occured during cache purge", error, purge_cache_err, "m1 contentHostingConfiguration")); + response->status, 3, &purge_node->m1_purge_info->m1_message, "Problem occured during cache purge", error, purge_cache_err, m1_contenthostingprovisioning_api, app_meta)); ogs_list_for_each_safe(&as_state->purge_content_hosting_cache, next, content_hosting_cache){ if (purge_node->purge_regex) { @@ -1309,7 +1378,8 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) next_action_for_application_server(as_state); break; DEFAULT - ogs_error("Unknown M3 Content Hosting Configuration operation [%s]", message.h.resource.component[1]); + ogs_error("Unknown M3 Content Hosting Configuration operation [%s]", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Content Hosting Configuration operation", message.h.resource.component[1], NULL, NULL, app_meta)); break; END break; @@ -1362,7 +1432,11 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) next_action_for_application_server(as_state); break; DEFAULT - ogs_error("Unknown M3 Content Hosting Configuratiobn GET operation [%s]", message.h.resource.component[1]); + char *err; + ogs_error("Unknown M3 Content Hosting Configuration operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + asprintf(&err, "Unknown M3 Content Hosting Configuration operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Content Hosting Configuration operation", err, NULL, NULL, app_meta)); + break; END break; @@ -1532,7 +1606,8 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) next_action_for_application_server(as_state); break; DEFAULT - ogs_error("Unknown M3 certificate operation [%s]", message.h.resource.component[1]); + ogs_error("Unknown M3 certificate operation [%s]", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 certificate operation.", message.h.resource.component[1], NULL, NULL, app_meta)); break; END break; @@ -1588,7 +1663,11 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) next_action_for_application_server(as_state); break; DEFAULT - ogs_error("Unknown M3 certificate GET operation [%s]", message.h.resource.component[1]); + char *err; + ogs_error("Unknown M3 certificate operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + asprintf(&err, "Unsupported M3 Certificate operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Certificate operation", err, NULL, NULL, app_meta)); + break; END break; @@ -1599,6 +1678,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) DEFAULT ogs_error("Unknown M3 operation [%s]", message.h.resource.component[0]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unsupported M3 operation", message.h.resource.component[0], NULL, NULL, app_meta)); break; END break; @@ -1718,5 +1798,5 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_error("No handler for event %s", msaf_event_get_name(e)); break; } + ogs_free(nf_name); } - diff --git a/src/5gmsaf/server.c b/src/5gmsaf/server.c index f81b7d2..3cd9500 100644 --- a/src/5gmsaf/server.c +++ b/src/5gmsaf/server.c @@ -14,21 +14,21 @@ program. If this file is missing then the license can be retrieved from #include "msaf-version.h" static bool nf_server_send_problem( - ogs_sbi_stream_t *stream, OpenAPI_problem_details_t *problem, char *interface); + ogs_sbi_stream_t *stream, OpenAPI_problem_details_t *problem, const nf_server_interface_metadata_t *interface, const nf_server_app_metadata_t *app); static ogs_sbi_response_t *nf_build_response( - ogs_sbi_message_t *message, int status, char *interface); + ogs_sbi_message_t *message, int status, const nf_server_interface_metadata_t *interface, const nf_server_app_metadata_t *app); static bool nf_build_content( ogs_sbi_http_message_t *http, ogs_sbi_message_t *message); static char *nf_build_json(ogs_sbi_message_t *message); -ogs_sbi_response_t *nf_server_new_response(char *location, char *content_type, time_t last_modified, char *etag, int cache_control, char *interface) +ogs_sbi_response_t *nf_server_new_response(char *location, char *content_type, time_t last_modified, char *etag, int cache_control, const nf_server_interface_metadata_t *interface, const nf_server_app_metadata_t *app) { ogs_sbi_response_t *response = NULL; - char *server_api_info = NULL; - char *server = NULL; + char *server_api_info = ((char*)""); + char *server = NULL; response = ogs_sbi_response_new(); ogs_expect_or_return_val(response, NULL); @@ -62,65 +62,16 @@ ogs_sbi_response_t *nf_server_new_response(char *location, char *content_type, t ogs_sbi_header_set(response->http.headers, "Cache-Control", response_cache_control); ogs_free(response_cache_control); } - - if(!interface){ - - server = ogs_msprintf("5GMSdAF-%s/%s %s/%s",msaf_self()->server_name, FIVEG_API_RELEASE, MSAF_NAME, MSAF_VERSION); - - - } else if(!strcmp(interface, "m1 provisioningSession")) - { - - server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", M1_PROVISIONINGSESSIONS_API_NAME, M1_PROVISIONINGSESSIONS_API_VERSION); - server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVEG_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); - - } else if(!strcmp(interface, "m1 contentHostingConfiguration")) - { - - server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", M1_CONTENTHOSTINGPROVISIONING_API_NAME, M1_CONTENTHOSTINGPROVISIONING_API_VERSION); - server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVEG_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); - - } else if(!strcmp(interface, "m1 contentProtocolsDiscovery")) - { - - server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", M1_CONTENTPROTOCOLSDISCOVERY_API_NAME, M1_CONTENTPROTOCOLSDISCOVERY_API_VERSION); - server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVEG_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); - - } - else if(!strcmp(interface, "m1 certificates")) - { - - server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", M1_SERVERCERTIFICATESPROVISIONING_API_NAME, M1_SERVERCERTIFICATESPROVISIONING_API_VERSION); - server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVEG_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); - - } else if(!strcmp(interface, "m3 contentHostingConfiguration")) - { - - server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", M3_CONTENTHOSTINGPROVISIONING_API_NAME, M3_CONTENTHOSTINGPROVISIONING_API_VERSION); - server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVEG_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); - - } else if(!strcmp(interface, "m3 certificates")) - { - - server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", M3_SERVERCERTIFICATESPROVISIONING_API_NAME, M3_SERVERCERTIFICATESPROVISIONING_API_VERSION); - server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVEG_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); - } - - else if(!strcmp(interface, "m5")) - { - - server_api_info = ogs_msprintf("(info.title=%s; info.version=%s)", M5_SERVICEACCESSINFORMATION_API_NAME, M5_SERVICEACCESSINFORMATION_API_VERSION); - server = ogs_msprintf("5GMSdAF-%s/%s %s %s/%s",msaf_self()->server_name, FIVEG_API_RELEASE, server_api_info, MSAF_NAME, MSAF_VERSION); - - } else { - - server = ogs_msprintf("5GMSdAF-%s/%s %s/%s",msaf_self()->server_name, FIVEG_API_RELEASE, MSAF_NAME, MSAF_VERSION); + + if (interface) { + server_api_info = ogs_msprintf(" (info.title=%s; info.version=%s)", interface->api_title, interface->api_version); } - + server = ogs_msprintf("%s/%s%s %s/%s",app->server_name, FIVEG_API_RELEASE, server_api_info, app->app_name, app->app_version); + if (interface) { + ogs_free(server_api_info); + } ogs_sbi_header_set(response->http.headers, "Server", server); - if(server_api_info) ogs_free(server_api_info); ogs_free(server); - return response; @@ -136,7 +87,7 @@ ogs_sbi_response_t *nf_server_populate_response(ogs_sbi_response_t *response, in } static bool nf_server_send_problem( - ogs_sbi_stream_t *stream, OpenAPI_problem_details_t *problem, char *interface) + ogs_sbi_stream_t *stream, OpenAPI_problem_details_t *problem, const nf_server_interface_metadata_t *interface, const nf_server_app_metadata_t *app) { ogs_sbi_message_t message; ogs_sbi_response_t *response = NULL; @@ -149,7 +100,7 @@ static bool nf_server_send_problem( message.http.content_type = (char*)"application/problem+json"; message.ProblemDetails = problem; - response = nf_build_response(&message, problem->status, interface); + response = nf_build_response(&message, problem->status, interface, app); ogs_assert(response); ogs_sbi_server_send_response(stream, response); @@ -160,7 +111,7 @@ static bool nf_server_send_problem( bool nf_server_send_error(ogs_sbi_stream_t *stream, int status, int number_of_components, ogs_sbi_message_t *message, - const char *title, const char *detail, cJSON * problem_detail, char *interface) + const char *title, const char *detail, cJSON * problem_detail, const nf_server_interface_metadata_t *interface, const nf_server_app_metadata_t *app) { OpenAPI_problem_details_t problem; OpenAPI_problem_details_t *problem_details = NULL; @@ -199,7 +150,7 @@ bool nf_server_send_error(ogs_sbi_stream_t *stream, problem.title = (char*)title; problem.detail = (char*)detail; - nf_server_send_problem(stream, &problem, interface); + nf_server_send_problem(stream, &problem, interface, app); if (problem.type) ogs_free(problem.type); @@ -212,13 +163,13 @@ bool nf_server_send_error(ogs_sbi_stream_t *stream, } ogs_sbi_response_t *nf_build_response( - ogs_sbi_message_t *message, int status, char *interface) + ogs_sbi_message_t *message, int status, const nf_server_interface_metadata_t *interface, const nf_server_app_metadata_t *app) { ogs_sbi_response_t *response = NULL; ogs_assert(message); - response = nf_server_new_response(NULL, NULL, 0, NULL, 0, interface); + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, interface, app); //response = ogs_sbi_response_new(); ogs_expect_or_return_val(response, NULL); diff --git a/src/5gmsaf/server.h b/src/5gmsaf/server.h index 3ccc74a..7c40cd3 100644 --- a/src/5gmsaf/server.h +++ b/src/5gmsaf/server.h @@ -18,11 +18,22 @@ program. If this file is missing then the license can be retrieved from extern "C" { #endif +typedef struct nf_server_interface_metadata_s { + const char *api_title; + const char *api_version; +} nf_server_interface_metadata_t; + +typedef struct nf_server_app_metadata_s { + const char *app_name; + const char *app_version; + const char *server_name; +} nf_server_app_metadata_t; + extern bool nf_server_send_error(ogs_sbi_stream_t *stream, int status, int number_of_components, ogs_sbi_message_t *message, - const char *title, const char *detail, cJSON * problem_detail, char *interface); + const char *title, const char *detail, cJSON * problem_detail, const nf_server_interface_metadata_t *interface, const nf_server_app_metadata_t *app); -extern ogs_sbi_response_t *nf_server_new_response(char *location, char *content_type, time_t last_modified, char *etag, int cache_control, char *interface); +extern ogs_sbi_response_t *nf_server_new_response(char *location, char *content_type, time_t last_modified, char *etag, int cache_control, const nf_server_interface_metadata_t *interface, const nf_server_app_metadata_t *app); extern ogs_sbi_response_t *nf_server_populate_response(ogs_sbi_response_t *response, int content_length, char *content, int status); #ifdef __cplusplus From 0d22a293231f1b77c39684809ee944ae3252e10c Mon Sep 17 00:00:00 2001 From: deva Date: Fri, 24 Feb 2023 16:42:15 +0000 Subject: [PATCH 08/48] Includes OPTIONS method for M1 API endpoints --- src/5gmsaf/msaf-sm.c | 203 +++++++++++++++++++++++++++++++++---------- src/5gmsaf/server.c | 11 ++- src/5gmsaf/server.h | 2 +- 3 files changed, 167 insertions(+), 49 deletions(-) diff --git a/src/5gmsaf/msaf-sm.c b/src/5gmsaf/msaf-sm.c index 0e46356..5f9534c 100644 --- a/src/5gmsaf/msaf-sm.c +++ b/src/5gmsaf/msaf-sm.c @@ -93,7 +93,6 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) const nf_server_interface_metadata_t *m1_contentprotocolsdiscovery_api = &m1_contentprotocolsdiscovery_api_metadata; const nf_server_interface_metadata_t *m1_servercertificatesprovisioning_api = &m1_servercertificatesprovisioning_api_metadata; const nf_server_interface_metadata_t *m3_contenthostingprovisioning_api = &m3_contenthostingprovisioning_api_metatdata; - const nf_server_interface_metadata_t *m3_servercertificatesprovisioning_api = &m3_servercertificatesprovisioning_api_metadata; const nf_server_interface_metadata_t *m5_serviceaccessinformation_api = &m5_serviceaccessinformation_api_metadata; const nf_server_app_metadata_t *app_meta = &app_metadata; @@ -113,6 +112,19 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) stream = e->h.sbi.data; ogs_assert(stream); + if (!strcmp(request->h.method, OGS_SBI_HTTP_METHOD_OPTIONS) && !strcmp(request->h.uri, "*")){ + char *methods = NULL; + ogs_sbi_response_t *response; + methods = ogs_msprintf("%s, %s, %s, %s, %s",OGS_SBI_HTTP_METHOD_POST, OGS_SBI_HTTP_METHOD_GET, OGS_SBI_HTTP_METHOD_PUT, OGS_SBI_HTTP_METHOD_DELETE, OGS_SBI_HTTP_METHOD_OPTIONS); + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, methods, NULL, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + ogs_free(methods); + break; + } + + rv = ogs_sbi_parse_header(&message, &request->h); if (rv != OGS_OK) { ogs_error("ogs_sbi_parse_header() failed"); @@ -255,6 +267,11 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) if (m1_purge_info->refs == 0) { ogs_free(m1_purge_info); // Send 204 back to M1 client + ogs_sbi_response_t *response; + response = nf_server_new_response(NULL, NULL, NULL, NULL, NULL, NULL, m1_contenthostingprovisioning_api, app_meta); + nf_server_populate_response(response, NULL, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); } } else { ogs_error("Unable to retrieve the Provisioning Session [%s]", message.h.resource.component[1]); @@ -318,7 +335,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) if (chc != NULL) { char *text; msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, m1_contentprotocolsdiscovery_api, app_meta); + response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, NULL, m1_contentprotocolsdiscovery_api, app_meta); text = cJSON_Print(chc); nf_server_populate_response(response, strlen(text), text, 201); ogs_assert(response); @@ -386,7 +403,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; } - response = nf_server_new_response(location, "application/x-pem-file", csr_cert->last_modified, csr_cert->server_certificate_hash, m1_server_certificates_response_max_age, m1_servercertificatesprovisioning_api, app_meta); + response = nf_server_new_response(location, "application/x-pem-file", csr_cert->last_modified, csr_cert->server_certificate_hash, m1_server_certificates_response_max_age, NULL, m1_servercertificatesprovisioning_api, app_meta); nf_server_populate_response(response, strlen(csr_cert->certificate), ogs_strdup(csr_cert->certificate), 200); @@ -411,7 +428,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_sbi_response_t *response; char *location; location = ogs_msprintf("%s/%s", request->h.uri, cert); - response = nf_server_new_response(location, NULL, 0, NULL, 0, m1_servercertificatesprovisioning_api, app_meta); + response = nf_server_new_response(location, NULL, 0, NULL, 0, NULL, m1_servercertificatesprovisioning_api, app_meta); nf_server_populate_response(response, 0, NULL, 200); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); @@ -428,7 +445,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; } - response = nf_server_new_response(location, NULL, new_cert->last_modified, new_cert->server_certificate_hash, m1_server_certificates_response_max_age, m1_servercertificatesprovisioning_api, app_meta); + response = nf_server_new_response(location, NULL, new_cert->last_modified, new_cert->server_certificate_hash, m1_server_certificates_response_max_age, NULL, m1_servercertificatesprovisioning_api, app_meta); nf_server_populate_response(response, 0, NULL, 200); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); @@ -481,7 +498,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { location = ogs_msprintf("%s%s", request->h.uri,msaf_provisioning_session->provisioningSessionId); } - response = nf_server_new_response(location, "application/json", msaf_provisioning_session->provisioningSessionReceived, msaf_provisioning_session->provisioningSessionHash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, m1_provisioningsession_api, app_meta); + response = nf_server_new_response(location, "application/json", msaf_provisioning_session->provisioningSessionReceived, msaf_provisioning_session->provisioningSessionHash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, m1_provisioningsession_api, app_meta); nf_server_populate_response(response, strlen(text), text, 201); ogs_assert(response); @@ -526,7 +543,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; } - response = nf_server_new_response(NULL, "application/x-pem-file", cert->last_modified, cert->server_certificate_hash, m1_server_certificates_response_max_age, m1_servercertificatesprovisioning_api, app_meta); + response = nf_server_new_response(NULL, "application/x-pem-file", cert->last_modified, cert->server_certificate_hash, m1_server_certificates_response_max_age, NULL, m1_servercertificatesprovisioning_api, app_meta); nf_server_populate_response(response, strlen(cert->certificate), ogs_strdup(cert->certificate), 200); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); @@ -578,7 +595,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *text; text = cJSON_Print(chc); - response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, m1_contenthostingprovisioning_api, app_meta); + response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, NULL, m1_contenthostingprovisioning_api, app_meta); ogs_assert(response); nf_server_populate_response(response, strlen(text), text, 200); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); @@ -608,7 +625,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) if(msaf_provisioning_session) { ogs_sbi_response_t *response; ogs_info("CONTENT_PROTOCOLS_DISCOVERY_JSON: %s", CONTENT_PROTOCOLS_DISCOVERY_JSON); - response = nf_server_new_response(NULL, "application/json", CONTENT_PROTOCOLS_DISCOVERY_JSON_TIME, CONTENT_PROTOCOLS_DISCOVERY_JSON_HASH, msaf_self()->config.server_response_cache_control->m1_content_protocols_response_max_age, m1_contentprotocolsdiscovery_api, app_meta); + response = nf_server_new_response(NULL, "application/json", CONTENT_PROTOCOLS_DISCOVERY_JSON_TIME, CONTENT_PROTOCOLS_DISCOVERY_JSON_HASH, msaf_self()->config.server_response_cache_control->m1_content_protocols_response_max_age, NULL, m1_contentprotocolsdiscovery_api, app_meta); ogs_assert(response); nf_server_populate_response(response, strlen(CONTENT_PROTOCOLS_DISCOVERY_JSON), ogs_strdup(CONTENT_PROTOCOLS_DISCOVERY_JSON), 200); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); @@ -632,7 +649,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *text; text = cJSON_Print(provisioning_session); - response = nf_server_new_response(NULL, "application/json", msaf_provisioning_session->provisioningSessionReceived, msaf_provisioning_session->provisioningSessionHash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, m1_provisioningsession_api, app_meta); + response = nf_server_new_response(NULL, "application/json", msaf_provisioning_session->provisioningSessionReceived, msaf_provisioning_session->provisioningSessionHash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, m1_provisioningsession_api, app_meta); nf_server_populate_response(response, strlen(text), text, 200); ogs_assert(response); @@ -757,7 +774,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) // response = ogs_sbi_response_new(); if (rv == 0){ - response = nf_server_new_response(NULL, NULL, 0, NULL, 0, m1_servercertificatesprovisioning_api, app_meta); + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_servercertificatesprovisioning_api, app_meta); nf_server_populate_response(response, 0, NULL, 204); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); @@ -823,7 +840,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) int rv; rv = server_cert_delete(message.h.resource.component[3]); if ((rv == 0) || (rv == 8)){ - response = nf_server_new_response(NULL, NULL, 0, NULL, 0, m1_servercertificatesprovisioning_api, app_meta); + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_servercertificatesprovisioning_api, app_meta); nf_server_populate_response(response, 0, NULL, 204); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); @@ -863,7 +880,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) msaf_delete_content_hosting_configuration(message.h.resource.component[1]); OpenAPI_content_hosting_configuration_free(msaf_provisioning_session->contentHostingConfiguration); msaf_provisioning_session->contentHostingConfiguration = NULL; - response = nf_server_new_response(NULL, NULL, 0, NULL, 0, m1_contenthostingprovisioning_api, app_meta); + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_contenthostingprovisioning_api, app_meta); ogs_assert(response); nf_server_populate_response(response, 0, NULL, 204); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); @@ -897,7 +914,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { provisioning_session->marked_for_deletion = 1; - response = nf_server_new_response(NULL, NULL, 0, NULL, 0, m1_provisioningsession_api, app_meta); + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_provisioningsession_api, app_meta); ogs_assert(response); nf_server_populate_response(response, 0, NULL, 202); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); @@ -910,27 +927,121 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) break; CASE(OGS_SBI_HTTP_METHOD_OPTIONS) - if (message.h.resource.component[1] && !strcmp(message.h.resource.component[2],"certificates") && message.h.resource.component[3]) { - ogs_sbi_response_t *response; - msaf_provisioning_session_t *provisioning_session = NULL; - provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if (provisioning_session) { - response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, m1_servercertificatesprovisioning_api, app_meta); + + if (!strcmp(message.h.resource.component[0],"provisioning-sessions")){ + ogs_sbi_response_t *response; + char *methods = NULL; + + if (message.h.resource.component[1]) { + msaf_provisioning_session_t *provisioning_session = NULL; + provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if (provisioning_session) { + if (message.h.resource.component[2]) { + + + if (!strcmp(message.h.resource.component[2],"certificates")) { + if (message.h.resource.component[3]) { + msaf_certificate_t *cert; + cert = server_cert_retrieve(message.h.resource.component[3]); + if(cert){ + methods = ogs_msprintf("%s, %s, %s, %s",OGS_SBI_HTTP_METHOD_GET, OGS_SBI_HTTP_METHOD_PUT, OGS_SBI_HTTP_METHOD_DELETE, OGS_SBI_HTTP_METHOD_OPTIONS); + response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + ogs_free(cert->certificate); + ogs_free(cert); + } else { + char *err = NULL; + ogs_error("Method [%s]: Unable to retrieve certificate [%s]", message.h.method, message.h.resource.component[3]); + asprintf(&err,"Method [%s]: Unable to retrieve certificate [%s]", message.h.method, message.h.resource.component[3]); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Unable to retrieve certificate.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + + } + } else { + methods = ogs_msprintf("%s",OGS_SBI_HTTP_METHOD_POST); + response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + } + + } else if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { + methods = ogs_msprintf("%s, %s, %s, %s, %s",OGS_SBI_HTTP_METHOD_POST, OGS_SBI_HTTP_METHOD_GET, OGS_SBI_HTTP_METHOD_PUT, OGS_SBI_HTTP_METHOD_DELETE, OGS_SBI_HTTP_METHOD_OPTIONS); + response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_contenthostingprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + + } else { + char *err = NULL; + asprintf(&err,"Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[2]); + ogs_error("Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[2]); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Target not yet supported.", err, NULL, NULL, app_meta)); + } + } else { + methods = ogs_msprintf("%s, %s, %s", OGS_SBI_HTTP_METHOD_GET, OGS_SBI_HTTP_METHOD_DELETE, OGS_SBI_HTTP_METHOD_OPTIONS); + response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_provisioningsession_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + + } + /* + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + + if(methods) ogs_free(methods); + */ + } else { + char *err = NULL; + int number_of_components; + const nf_server_interface_metadata_t *interface; + if (message.h.resource.component[2]){ + if (!strcmp(message.h.resource.component[2],"certificates")) { + number_of_components = 2; + if (message.h.resource.component[3]) { + number_of_components = 3; + } + interface = m1_servercertificatesprovisioning_api; + } else if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { + number_of_components = 2; + interface = m1_contenthostingprovisioning_api; + + } + } else if (message.h.resource.component[0]){ + if (!strcmp(message.h.resource.component[0],"provisioning-sessions")){ + number_of_components = 0; + if (message.h.resource.component[1]) { + number_of_components = 1; + } + interface = m1_provisioningsession_api; + + } + } + asprintf(&err,"Method [%s]: [%s] - Provisioning Session [%s] does not exist.", message.h.method, message.h.resource.component[2], message.h.resource.component[1]); + ogs_error("Method [%s]: [%s] - Provisioning Session [%s] does not exist.", message.h.method, message.h.resource.component[2], message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, number_of_components, &message, "Provisioning Session does not exists.", err, NULL, interface, app_meta)); + + } + + } else { + methods = ogs_msprintf("%s, %s",OGS_SBI_HTTP_METHOD_POST, OGS_SBI_HTTP_METHOD_OPTIONS); + response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_provisioningsession_api, app_meta); nf_server_populate_response(response, 0, NULL, 204); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - - - } else { - char *err = NULL; - asprintf(&err,"Method [%s] - [%s]:[%s] - Provisioning Session [%s] does not exist.", message.h.method, message.h.resource.component[2], message.h.resource.component[3], message.h.resource.component[1]); - ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - } - } + if(methods) ogs_free(methods); + } else { + char *err = NULL; + asprintf(&err,"Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[0]); + ogs_error("Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[0]); + ogs_assert(true == nf_server_send_error(stream, 404, 0, &message, "Target not yet supported.", err, NULL, m1_provisioningsession_api, app_meta)); + + } break; DEFAULT @@ -985,7 +1096,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_sbi_response_t *response; char *text; text = cJSON_Print(service_access_information); - response = nf_server_new_response(NULL, "application/json", msaf_provisioning_session->serviceAccessInformationCreated, msaf_provisioning_session->serviceAccessInformationHash, msaf_self()->config.server_response_cache_control->m5_service_access_information_response_max_age, m5_serviceaccessinformation_api, app_meta); + response = nf_server_new_response(NULL, "application/json", msaf_provisioning_session->serviceAccessInformationCreated, msaf_provisioning_session->serviceAccessInformationHash, msaf_self()->config.server_response_cache_control->m5_service_access_information_response_max_age, NULL, m5_serviceaccessinformation_api, app_meta); nf_server_populate_response(response, strlen(text), text, 201); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); @@ -1135,21 +1246,21 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) if(!purge_node->m1_purge_info->refs){ // send M1 response with total from purge_node->m1_purge_info->purged_entries_total // ogs_free(purge_node->m1_purge_info); - ogs_sbi_response_t *response; - cJSON *purged_entries_total_json = cJSON_CreateNumber(purge_node->m1_purge_info->purged_entries_total); - char *purged_entries_total = cJSON_Print(purged_entries_total_json); - response = ogs_sbi_response_new(); - response->http.content_length = strlen(purged_entries_total); - response->http.content = purged_entries_total; - response->status = 200; - ogs_sbi_header_set(response->http.headers, "Content-Type", "application/json"); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(purge_node->m1_purge_info->m1_stream, response)); - - if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); - if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); - if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); - ogs_free(content_hosting_cache); + ogs_sbi_response_t *response; + cJSON *purged_entries_total_json = cJSON_CreateNumber(purge_node->m1_purge_info->purged_entries_total); + char *purged_entries_total = cJSON_Print(purged_entries_total_json); + response = ogs_sbi_response_new(); + response->http.content_length = strlen(purged_entries_total); + response->http.content = purged_entries_total; + response->status = 200; + ogs_sbi_header_set(response->http.headers, "Content-Type", "application/json"); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(purge_node->m1_purge_info->m1_stream, response)); + + if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); + if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); + if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); + ogs_free(content_hosting_cache); } msaf_application_server_state_log(&as_state->purge_content_hosting_cache, "Purge Content Hosting Cache list"); diff --git a/src/5gmsaf/server.c b/src/5gmsaf/server.c index 3cd9500..19232db 100644 --- a/src/5gmsaf/server.c +++ b/src/5gmsaf/server.c @@ -24,7 +24,7 @@ static bool nf_build_content( static char *nf_build_json(ogs_sbi_message_t *message); -ogs_sbi_response_t *nf_server_new_response(char *location, char *content_type, time_t last_modified, char *etag, int cache_control, const nf_server_interface_metadata_t *interface, const nf_server_app_metadata_t *app) +ogs_sbi_response_t *nf_server_new_response(char *location, char *content_type, time_t last_modified, char *etag, int cache_control, char *allow_methods, const nf_server_interface_metadata_t *interface, const nf_server_app_metadata_t *app) { ogs_sbi_response_t *response = NULL; char *server_api_info = ((char*)""); @@ -62,6 +62,13 @@ ogs_sbi_response_t *nf_server_new_response(char *location, char *content_type, t ogs_sbi_header_set(response->http.headers, "Cache-Control", response_cache_control); ogs_free(response_cache_control); } + + if(allow_methods) + { + + ogs_sbi_header_set(response->http.headers, "Allow", allow_methods); + } + if (interface) { server_api_info = ogs_msprintf(" (info.title=%s; info.version=%s)", interface->api_title, interface->api_version); @@ -169,7 +176,7 @@ ogs_sbi_response_t *nf_build_response( ogs_assert(message); - response = nf_server_new_response(NULL, NULL, 0, NULL, 0, interface, app); + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, interface, app); //response = ogs_sbi_response_new(); ogs_expect_or_return_val(response, NULL); diff --git a/src/5gmsaf/server.h b/src/5gmsaf/server.h index 7c40cd3..60da40c 100644 --- a/src/5gmsaf/server.h +++ b/src/5gmsaf/server.h @@ -33,7 +33,7 @@ extern bool nf_server_send_error(ogs_sbi_stream_t *stream, int status, int number_of_components, ogs_sbi_message_t *message, const char *title, const char *detail, cJSON * problem_detail, const nf_server_interface_metadata_t *interface, const nf_server_app_metadata_t *app); -extern ogs_sbi_response_t *nf_server_new_response(char *location, char *content_type, time_t last_modified, char *etag, int cache_control, const nf_server_interface_metadata_t *interface, const nf_server_app_metadata_t *app); +extern ogs_sbi_response_t *nf_server_new_response(char *location, char *content_type, time_t last_modified, char *etag, int cache_control, char *allow_methods, const nf_server_interface_metadata_t *interface, const nf_server_app_metadata_t *app); extern ogs_sbi_response_t *nf_server_populate_response(ogs_sbi_response_t *response, int content_length, char *content, int status); #ifdef __cplusplus From 8125724937b42136ed67f5a18e189701b6bac729 Mon Sep 17 00:00:00 2001 From: deva Date: Wed, 1 Mar 2023 14:45:45 +0000 Subject: [PATCH 09/48] server response header modified --- src/5gmsaf/response-cache-control.c | 9 +++------ src/5gmsaf/response-cache-control.h | 4 ++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/5gmsaf/response-cache-control.c b/src/5gmsaf/response-cache-control.c index b095d12..42703fc 100644 --- a/src/5gmsaf/response-cache-control.c +++ b/src/5gmsaf/response-cache-control.c @@ -10,11 +10,7 @@ program. If this file is missing then the license can be retrieved from #include "context.h" #include "response-cache-control.h" -/* -#define SERVER_RESPONSE_MAX_AGE 60 -#define M1_CONTENT_PROTOCOLS_RESPONSE_MAX_AGE 86400 -*/ void msaf_server_response_cache_control_set(void) { msaf_server_response_cache_control_t *server_response_cache_control = NULL; @@ -22,16 +18,17 @@ void msaf_server_response_cache_control_set(void) ogs_assert(server_response_cache_control); server_response_cache_control->m1_provisioning_session_response_max_age = SERVER_RESPONSE_MAX_AGE; server_response_cache_control->m1_content_hosting_configurations_response_max_age = SERVER_RESPONSE_MAX_AGE; + server_response_cache_control->m1_server_certificates_response_max_age = SERVER_RESPONSE_MAX_AGE; server_response_cache_control->m1_content_protocols_response_max_age = M1_CONTENT_PROTOCOLS_RESPONSE_MAX_AGE; server_response_cache_control->m5_service_access_information_response_max_age = SERVER_RESPONSE_MAX_AGE; - msaf_self()->config.server_response_cache_control = server_response_cache_control; } -void msaf_server_response_cache_control_set_from_config(int m1_provisioning_session_response_max_age, int m1_content_hosting_configurations_response_max_age, int m1_content_protocols_response_max_age, int m5_service_access_information_response_max_age) +void msaf_server_response_cache_control_set_from_config(int m1_provisioning_session_response_max_age, int m1_content_hosting_configurations_response_max_age, int m1_server_certificates_response_max_age, int m1_content_protocols_response_max_age, int m5_service_access_information_response_max_age) { msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age = m1_provisioning_session_response_max_age; msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age = m1_content_hosting_configurations_response_max_age; + msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age = m1_server_certificates_response_max_age; msaf_self()->config.server_response_cache_control->m1_content_protocols_response_max_age = m1_content_protocols_response_max_age; msaf_self()->config.server_response_cache_control->m5_service_access_information_response_max_age = m5_service_access_information_response_max_age; } diff --git a/src/5gmsaf/response-cache-control.h b/src/5gmsaf/response-cache-control.h index 806f64d..ab680c1 100644 --- a/src/5gmsaf/response-cache-control.h +++ b/src/5gmsaf/response-cache-control.h @@ -23,13 +23,13 @@ extern "C" { typedef struct msaf_server_response_cache_control_s { int m1_provisioning_session_response_max_age; int m1_content_hosting_configurations_response_max_age; + int m1_server_certificates_response_max_age; int m1_content_protocols_response_max_age; int m5_service_access_information_response_max_age; }msaf_server_response_cache_control_t; extern void msaf_server_response_cache_control_set(void); - -extern void msaf_server_response_cache_control_set_from_config(int m1_provisioning_session_response_max_age, int m1_content_hosting_configurations_response_max_age, int m1_content_protocols_response_max_age, int m5_service_access_information_response_max_age); +extern void msaf_server_response_cache_control_set_from_config(int m1_provisioning_session_response_max_age, int m1_content_hosting_configurations_response_max_age, int m1_server_certificates_response_max_age, int m1_content_protocols_response_max_age, int m5_service_access_information_response_max_age); #ifdef __cplusplus From cd31258d772b14654f73c2fce29df8ab23c9455c Mon Sep 17 00:00:00 2001 From: deva Date: Wed, 1 Mar 2023 14:53:40 +0000 Subject: [PATCH 10/48] cert manager modified --- src/5gmsaf/certmgr.c | 87 +++++++++++++++++++++++++++++--------------- src/5gmsaf/certmgr.h | 3 ++ 2 files changed, 60 insertions(+), 30 deletions(-) diff --git a/src/5gmsaf/certmgr.c b/src/5gmsaf/certmgr.c index 67e164e..247d64a 100644 --- a/src/5gmsaf/certmgr.c +++ b/src/5gmsaf/certmgr.c @@ -17,6 +17,7 @@ program. If this file is missing then the license can be retrieved from static ogs_proc_t process[MAX_CHILD_PROCESS]; static int process_num = 0; +static msaf_certificate_t *msaf_certificate_populate(char *certid, char *cert, int out_return_code); int server_cert_delete(char *certid) { @@ -67,13 +68,8 @@ msaf_certificate_t *server_cert_retrieve(char *certid) char *command; char *rv = NULL; size_t cert_size = 0; - size_t cert_reserved = 0; - char *ts = NULL; - char *etag_cert = NULL; - char *etag=NULL; - char *buff = NULL; - char *certificate = NULL; - + size_t cert_reserved = 0; + command = ogs_msprintf("-c publiccert %s", certid); commandLine[0] = msaf_self()->config.certificateManager; @@ -99,24 +95,16 @@ msaf_certificate_t *server_cert_retrieve(char *certid) cert = ogs_realloc(cert,cert_reserved); } strcat(cert,buf); - - } - - buff = ogs_strdup(cert); - ts = strtok_r(buff,":",&etag_cert); - etag = strtok_r(etag_cert,":",&certificate); + } ret = ogs_proc_join(current, &out_return_code); ogs_assert(ret == 0); ret = ogs_proc_destroy(current); ogs_assert(ret == 0); ogs_free(command); - msaf_certificate = ogs_calloc(1, sizeof(msaf_certificate_t)); - ogs_assert(msaf_certificate); - - msaf_certificate->id = certid; - msaf_certificate->certificate = cert; - msaf_certificate->return_code = out_return_code; - + if(!out_return_code){ + msaf_certificate = msaf_certificate_populate(certid, cert, out_return_code); + ogs_assert(msaf_certificate); + } return msaf_certificate; } @@ -171,8 +159,7 @@ msaf_certificate_t *server_cert_new(char *operation, char *operation_params) char *certificate; msaf_certificate_t *msaf_certificate = NULL; size_t cert_size = 0; - size_t cert_reserved = 0; - + size_t cert_reserved = 0; msaf_application_server_node_t *msaf_as = NULL; msaf_as = ogs_list_first(&msaf_self()->config.applicationServers_list); canonical_domain_name = msaf_as->canonicalHostname; @@ -216,13 +203,8 @@ msaf_certificate_t *server_cert_new(char *operation, char *operation_params) ret = ogs_proc_destroy(current); ogs_assert(ret == 0); ogs_free(command); - msaf_certificate = ogs_calloc(1, sizeof(msaf_certificate_t)); - ogs_assert(msaf_certificate); - - msaf_certificate->id = id; - msaf_certificate->certificate = cert; - msaf_certificate->return_code = out_return_code; - + msaf_certificate = msaf_certificate_populate(id, cert, out_return_code); + ogs_assert(msaf_certificate); return msaf_certificate; } @@ -267,4 +249,49 @@ char *check_in_cert_list(char *canonical_domain_name) ogs_assert(ret == 0); ogs_free(operation); return certificate; -} \ No newline at end of file +} + +static msaf_certificate_t *msaf_certificate_populate(char *certid, char *cert, int out_return_code) +{ + msaf_certificate_t *msaf_certificate = NULL; + char *token; + char *string; + char *key; + char *value; + char *ptr; + msaf_certificate = ogs_calloc(1, sizeof(msaf_certificate_t)); + ogs_assert(msaf_certificate); + msaf_certificate->id = certid; + msaf_certificate->return_code = out_return_code; + ptr = string = ogs_strdup(cert); + while ((token = strsep(&string, "&")) != NULL) + { + if(strcmp(token,"")){ + key = strtok_r(token,"=",&value); + ogs_info("key: %s, value: %s", key, value); + if (!strcmp(key,"timestamp")){ + ogs_debug("key: %s, value: %s", key, value); + msaf_certificate->last_modified = str_to_time(value); + } else if (!strcmp(key,"max-age")){ + ogs_debug("key: %s, value: %s", key, value); + if(!strcmp(value,"")){ + msaf_certificate->cache_control_max_age = 0; + } else { + msaf_certificate->cache_control_max_age = ascii_to_long(value); + } + } else if (!strcmp(key,"hash")){ + ogs_debug("key: %s, value: %s", key, value); + msaf_certificate->server_certificate_hash = value; + } else if (!strcmp(key,"certificate")){ + ogs_debug("key: %s, value: %s", key, value); + msaf_certificate->certificate = ogs_strdup(value); + } else { + ogs_debug("Unrecognised key: %s, value: %s", key, value); + } + + } + + } + ogs_free(ptr); + return msaf_certificate; +} diff --git a/src/5gmsaf/certmgr.h b/src/5gmsaf/certmgr.h index 181c2af..1532651 100644 --- a/src/5gmsaf/certmgr.h +++ b/src/5gmsaf/certmgr.h @@ -21,6 +21,9 @@ extern "C" { typedef struct msaf_certificate_s { char *id; char *certificate; + time_t last_modified; + char *server_certificate_hash; + int cache_control_max_age; int return_code; } msaf_certificate_t; From a5b06abfd63cb2a2033da90aef77fa671e3199b4 Mon Sep 17 00:00:00 2001 From: deva Date: Wed, 1 Mar 2023 15:20:37 +0000 Subject: [PATCH 11/48] content protocols discovery header inclusion --- src/5gmsaf/msaf-sm.h | 1 + src/5gmsaf/utilities.c | 21 +++++++++++++++++++++ src/5gmsaf/utilities.h | 6 ++++++ 3 files changed, 28 insertions(+) diff --git a/src/5gmsaf/msaf-sm.h b/src/5gmsaf/msaf-sm.h index a4d06a3..5a3d53d 100644 --- a/src/5gmsaf/msaf-sm.h +++ b/src/5gmsaf/msaf-sm.h @@ -12,6 +12,7 @@ program. If this file is missing then the license can be retrieved from #define MSAF_SM_H #include "event.h" +#include "ContentProtocolsDiscovery_body.h" #ifdef __cplusplus extern "C" { diff --git a/src/5gmsaf/utilities.c b/src/5gmsaf/utilities.c index ffe0b5b..7b3e12b 100644 --- a/src/5gmsaf/utilities.c +++ b/src/5gmsaf/utilities.c @@ -17,6 +17,15 @@ program. If this file is missing then the license can be retrieved from #include #include "utilities.h" +time_t str_to_time(char *str_time) +{ + static time_t time; + struct tm tm = {0}; + strptime(str_time, "%a, %d %b %Y %H:%M:%S %Z", &tm); + time = mktime(&tm); + return time; +} + char *get_time(time_t time_epoch) { struct tm *ts; @@ -112,6 +121,18 @@ long int ascii_to_long(const char *str) return ret; } +uint16_t ascii_to_uint16(const char *str) +{ + long int ret; + ret = ascii_to_long(str); + if (ret > UINT16_MAX) + { + ogs_error("[%s] cannot be greater than [%d]", str, UINT16_MAX); + ret = 0; + } + return ret; +} + cJSON *create_cjson_number_object(char *name, int value) { cJSON *item = NULL; diff --git a/src/5gmsaf/utilities.h b/src/5gmsaf/utilities.h index 0a69b1f..2039af2 100644 --- a/src/5gmsaf/utilities.h +++ b/src/5gmsaf/utilities.h @@ -11,9 +11,13 @@ program. If this file is missing then the license can be retrieved from #ifndef MSAF_UTILITIES_H #define MSAF_UTILITIES_H +#define _XOPEN_SOURCE +#define __USE_XOPEN + #include #include #include +#include #include "ogs-app.h" #include "context.h" @@ -25,8 +29,10 @@ extern char *read_file(const char *filename); extern char *get_path(const char *file); extern char *rebase_path(const char *base, const char *file); extern long int ascii_to_long(const char *str); +extern uint16_t ascii_to_uint16(const char *str); extern int str_match(const char *line, const char *word_to_find); extern char *get_time(time_t time_epoch); +extern time_t str_to_time(char *str_time); #ifdef __cplusplus } From 5820bcbe650ed00fded372cd085c21231735353b Mon Sep 17 00:00:00 2001 From: deva Date: Wed, 1 Mar 2023 19:47:48 +0000 Subject: [PATCH 12/48] Install certmgr during build --- {examples => src/5gmsaf}/certmgr | 2 +- src/5gmsaf/meson.build | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) rename {examples => src/5gmsaf}/certmgr (99%) diff --git a/examples/certmgr b/src/5gmsaf/certmgr similarity index 99% rename from examples/certmgr rename to src/5gmsaf/certmgr index ff6a75b..b3fefcb 100755 --- a/examples/certmgr +++ b/src/5gmsaf/certmgr @@ -20,7 +20,7 @@ scriptdir=`cd "$scriptdir"; pwd` # Variables default_cert_op= cert_operation= -cert_store="/home/ubuntu/certificate" +cert_store="@path@" common_name= server_certificate_resource_id= cert_status= diff --git a/src/5gmsaf/meson.build b/src/5gmsaf/meson.build index 68f79bd..ca40ef0 100644 --- a/src/5gmsaf/meson.build +++ b/src/5gmsaf/meson.build @@ -244,3 +244,22 @@ foreach conf_file : msaf_config_source gen = configure_file(input : conf_file, copy : true, output : conf_file) meson.add_install_script(python3_exe, '-c', install_conf.format(gen, open5gs_sysconfdir)) endforeach + +cert_path = join_paths(meson.current_build_dir(), 'certificate') +mkdir_cert_result = run_command(['mkdir', '-p', cert_path], check: true, capture: false) + + +tools_path = join_paths(meson.current_build_dir(), 'tools') +mkdir_tools_result = run_command(['mkdir', '-p', tools_path], check: true, capture: false) + +cert_conf_data = configuration_data() +cert_conf_data.set('path', cert_path) +cert_mgr = configure_file(input : 'certmgr', + output : 'certmgr', + configuration : cert_conf_data) +meson.add_install_script(python3_exe, '-c', install_conf.format(cert_mgr, open5gs_sysconfdir)) + +cert_mgr_file = join_paths(meson.current_build_dir(), 'certmgr') + +mkdir_cert_mgr_result = run_command(['mv', cert_mgr_file, tools_path], check: true, capture: false) + From 3e44e1a1131f38b888f7ded0e4ea8c363cc8c15a Mon Sep 17 00:00:00 2001 From: deva Date: Thu, 2 Mar 2023 14:17:28 +0000 Subject: [PATCH 13/48] latest version: certmgr --- src/5gmsaf/certmgr | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/5gmsaf/certmgr b/src/5gmsaf/certmgr index b3fefcb..21390a7 100755 --- a/src/5gmsaf/certmgr +++ b/src/5gmsaf/certmgr @@ -20,11 +20,12 @@ scriptdir=`cd "$scriptdir"; pwd` # Variables default_cert_op= cert_operation= -cert_store="@path@" +cert_store=""@path@"" common_name= server_certificate_resource_id= cert_status= cert_subject= +cache_control_max_age=70 # Parse command line arguments ARGS=`getopt -n "$scriptname" -o 'c:h' -l 'cert-operation:,help' -s sh -- "$@"` @@ -134,7 +135,14 @@ new_csr() { cert_store_check >&2 openssl req -new -newkey rsa:2048 -batch -nodes -keyout "$cert_store/private/$server_certificate_resource_id.pem" -out "$cert_store/csrs/$server_certificate_resource_id.pem" -subj "/C=GB/L=London/CN=$common_name" -addext "subjectAltName=DNS:$common_name" > /dev/null 2>&1 - cat "$cert_store/csrs/$server_certificate_resource_id.pem" + #cat "$cert_store/csrs/$server_certificate_resource_id.pem" + ts=`stat -c '%Y' "$cert_store/csrs/$server_certificate_resource_id.pem"` + timestamp=`TZ=GMT date --date=@$ts +'%a, %d %b %Y %H:%M:%S %Z'` + hashsum=($(sha256sum "$cert_store/csrs/$server_certificate_resource_id.pem")) + cert=`cat $cert_store/csrs/$server_certificate_resource_id.pem` + + echo -e "timestamp=$timestamp&hash=$hashsum&max-age=$cache_control_max_age&certificate=$cert" + exit 0 } @@ -149,7 +157,14 @@ new_cert() { openssl x509 -req -CA "$cert_store/public/ca.crt" -CAkey "$cert_store/private/ca.key" -CAcreateserial -in "$cert_store/csrs/$server_certificate_resource_id.pem" -out "$cert_store/public/$server_certificate_resource_id.pem" -days 90 > /dev/null 2>&1 - cat "$cert_store/public/$server_certificate_resource_id.pem" + ts=`stat -c '%Y' "$cert_store/public/$server_certificate_resource_id.pem"` + timestamp=`TZ=GMT date --date=@$ts +'%a, %d %b %Y %H:%M:%S %Z'` + hashsum=($(sha256sum "$cert_store/public/$server_certificate_resource_id.pem")) + + cert=`cat "$cert_store/public/$server_certificate_resource_id.pem"` + + echo -e "timestamp=$timestamp&hash=$hashsum&max-age=$cache_control_max_age&certificate=$cert" + exit 0 } @@ -167,14 +182,14 @@ public_cert_get() { # cat $cert_store/public/$server_certificate_resource_id.pem $cert_store/public/ca.crt - ts=`stat -c '%Y' /etc/hosts`; TZ=GMT date --date=@$ts +'%a, %d %b %Y %H:%M:%S %Z' > /dev/null 2>&1 - etag=`sha256sum "$cert_store/public/$server_certificate_resource_id.pem"` - + ts=`stat -c '%Y' "$cert_store/public/$server_certificate_resource_id.pem"` + timestamp=`TZ=GMT date --date=@$ts +'%a, %d %b %Y %H:%M:%S %Z'` + hashsum=($(sha256sum "$cert_store/public/$server_certificate_resource_id.pem")) + cert=`cat $cert_store/public/$server_certificate_resource_id.pem` #printf '%s\t%s\t%s\n' \ # "$ts" "$etag" `cat "$cert_store/public/$server_certificate_resource_id.pem"` - - echo -e "$ts:$etag:`cat $cert_store/public/$server_certificate_resource_id.pem`" + echo -e "timestamp=$timestamp&hash=$hashsum&max-age=$cache_control_max_age&certificate=$cert" exit 0 } @@ -186,7 +201,14 @@ server_cert_get() { exit 8 fi - cat $cert_store/public/$server_certificate_resource_id.pem $cert_store/private/$server_certificate_resource_id.pem + + ts=`stat -c '%Y' "$cert_store/public/$server_certificate_resource_id.pem"` + timestamp=`TZ=GMT date --date=@$ts +'%a, %d %b %Y %H:%M:%S %Z'` + hashsum=($(sha256sum "$cert_store/public/$server_certificate_resource_id.pem")) + cert=`cat $cert_store/public/$server_certificate_resource_id.pem $cert_store/private/$server_certificate_resource_id.pem` + + echo -e "timestamp=$timestamp&hash=$hashsum&max-age=$cache_control_max_age&certificate=$cert" + exit 0 } From 79e5887b31526cbf61ff2250ec2675d6325cd08d Mon Sep 17 00:00:00 2001 From: deva Date: Fri, 3 Mar 2023 09:41:45 +0000 Subject: [PATCH 14/48] Modified certmgr header handling --- src/5gmsaf/certmgr | 21 ++++++--------------- src/5gmsaf/certmgr.c | 38 ++++++++++++++++++++++++++------------ src/5gmsaf/msaf-sm.c | 9 ++++++--- src/5gmsaf/msaf.yaml | 24 +++++++++++++++++------- src/5gmsaf/utilities.c | 15 +++++++++++++++ src/5gmsaf/utilities.h | 1 + 6 files changed, 71 insertions(+), 37 deletions(-) diff --git a/src/5gmsaf/certmgr b/src/5gmsaf/certmgr index 21390a7..55b5d18 100755 --- a/src/5gmsaf/certmgr +++ b/src/5gmsaf/certmgr @@ -20,7 +20,7 @@ scriptdir=`cd "$scriptdir"; pwd` # Variables default_cert_op= cert_operation= -cert_store=""@path@"" +cert_store="@cert_path@" common_name= server_certificate_resource_id= cert_status= @@ -140,9 +140,7 @@ new_csr() { timestamp=`TZ=GMT date --date=@$ts +'%a, %d %b %Y %H:%M:%S %Z'` hashsum=($(sha256sum "$cert_store/csrs/$server_certificate_resource_id.pem")) cert=`cat $cert_store/csrs/$server_certificate_resource_id.pem` - - echo -e "timestamp=$timestamp&hash=$hashsum&max-age=$cache_control_max_age&certificate=$cert" - + echo -e "Last-Modified: $timestamp\nETag: $hashsum\nCache-Control: max-age= $cache_control_max_age\n$cert" exit 0 } @@ -162,9 +160,7 @@ new_cert() { hashsum=($(sha256sum "$cert_store/public/$server_certificate_resource_id.pem")) cert=`cat "$cert_store/public/$server_certificate_resource_id.pem"` - - echo -e "timestamp=$timestamp&hash=$hashsum&max-age=$cache_control_max_age&certificate=$cert" - + echo -e "Last-Modified: $timestamp\nETag: $hashsum\nCache-Control: max-age= $cache_control_max_age\n$cert" exit 0 } @@ -185,11 +181,8 @@ public_cert_get() { ts=`stat -c '%Y' "$cert_store/public/$server_certificate_resource_id.pem"` timestamp=`TZ=GMT date --date=@$ts +'%a, %d %b %Y %H:%M:%S %Z'` hashsum=($(sha256sum "$cert_store/public/$server_certificate_resource_id.pem")) - cert=`cat $cert_store/public/$server_certificate_resource_id.pem` - #printf '%s\t%s\t%s\n' \ - # "$ts" "$etag" `cat "$cert_store/public/$server_certificate_resource_id.pem"` - - echo -e "timestamp=$timestamp&hash=$hashsum&max-age=$cache_control_max_age&certificate=$cert" + cert=`cat $cert_store/public/$server_certificate_resource_id.pem` + echo -e "Last-Modified: $timestamp\nETag: $hashsum\nCache-Control: max-age= $cache_control_max_age\n$cert" exit 0 } @@ -206,9 +199,7 @@ server_cert_get() { timestamp=`TZ=GMT date --date=@$ts +'%a, %d %b %Y %H:%M:%S %Z'` hashsum=($(sha256sum "$cert_store/public/$server_certificate_resource_id.pem")) cert=`cat $cert_store/public/$server_certificate_resource_id.pem $cert_store/private/$server_certificate_resource_id.pem` - - echo -e "timestamp=$timestamp&hash=$hashsum&max-age=$cache_control_max_age&certificate=$cert" - + echo -e "Last-Modified: $timestamp\nEtag: $hashsum\nMax-age: $cache_control_max_age\n$cert" exit 0 } diff --git a/src/5gmsaf/certmgr.c b/src/5gmsaf/certmgr.c index 247d64a..bda297c 100644 --- a/src/5gmsaf/certmgr.c +++ b/src/5gmsaf/certmgr.c @@ -257,41 +257,55 @@ static msaf_certificate_t *msaf_certificate_populate(char *certid, char *cert, i char *token; char *string; char *key; + char *val; char *value; char *ptr; + char *populated_certificate; msaf_certificate = ogs_calloc(1, sizeof(msaf_certificate_t)); ogs_assert(msaf_certificate); msaf_certificate->id = certid; msaf_certificate->return_code = out_return_code; + populated_certificate = ogs_calloc(1, strlen(cert)); ptr = string = ogs_strdup(cert); - while ((token = strsep(&string, "&")) != NULL) + while ((token = strsep(&string, "\n")) != NULL) { - if(strcmp(token,"")){ - key = strtok_r(token,"=",&value); - ogs_info("key: %s, value: %s", key, value); - if (!strcmp(key,"timestamp")){ + if(strstr(token, "Last-Modified:") || strstr(token, "ETag:") || strstr(token, "Cache-Control: max-age=")){ + key = strtok_r(token,":",&val); + ogs_info("key: %s, value: %s", key, val); + value = ogs_calloc(1, strlen(val)); + without_spaces(value, val); + ogs_assert(value); + if (!strcmp(key,"Last-Modified")){ ogs_debug("key: %s, value: %s", key, value); msaf_certificate->last_modified = str_to_time(value); - } else if (!strcmp(key,"max-age")){ + ogs_free(value); + } else if (!strcmp(key,"Cache-Control")){ + char *max_age_key; + char *max_age_value; + char *max_age = ogs_strdup(value); + max_age_key = strtok_r(max_age,"=",&max_age_value); + without_spaces(value, max_age_value); ogs_debug("key: %s, value: %s", key, value); if(!strcmp(value,"")){ msaf_certificate->cache_control_max_age = 0; } else { msaf_certificate->cache_control_max_age = ascii_to_long(value); } - } else if (!strcmp(key,"hash")){ + ogs_free(max_age); + ogs_free(value); + } else if (!strcmp(key,"ETag")){ ogs_debug("key: %s, value: %s", key, value); msaf_certificate->server_certificate_hash = value; - } else if (!strcmp(key,"certificate")){ - ogs_debug("key: %s, value: %s", key, value); - msaf_certificate->certificate = ogs_strdup(value); } else { ogs_debug("Unrecognised key: %s, value: %s", key, value); } + } else { + strcat(populated_certificate,token); + strcat(populated_certificate,"\n"); } - - } + } + msaf_certificate->certificate = populated_certificate; ogs_free(ptr); return msaf_certificate; } diff --git a/src/5gmsaf/msaf-sm.c b/src/5gmsaf/msaf-sm.c index 5f9534c..102c9ca 100644 --- a/src/5gmsaf/msaf-sm.c +++ b/src/5gmsaf/msaf-sm.c @@ -410,9 +410,9 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); ogs_free(location); - ogs_free(csr_cert->certificate); - ogs_free(csr_cert); - + if(csr_cert->server_certificate_hash) ogs_free(csr_cert->server_certificate_hash); + if(csr_cert->certificate) ogs_free(csr_cert->certificate); + ogs_free(csr_cert); return; } if (ogs_list_first(&msaf_provisioning_session->msaf_application_servers) == NULL) { @@ -450,6 +450,9 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); ogs_free(location); + if(new_cert->server_certificate_hash) ogs_free(new_cert->server_certificate_hash); + if (new_cert->certificate) ogs_free(new_cert->certificate); + ogs_free(new_cert); diff --git a/src/5gmsaf/msaf.yaml b/src/5gmsaf/msaf.yaml index dc5635f..789fb15 100644 --- a/src/5gmsaf/msaf.yaml +++ b/src/5gmsaf/msaf.yaml @@ -8,7 +8,8 @@ # #=========================================================================== # -# logger: +logger: + level: debug # # o Set OGS_LOG_INFO to all domain level # - If `level` is omitted, the default level is OGS_LOG_INFO) @@ -130,17 +131,26 @@ logger: # * That is, 'no_service_names' has no effect. # msaf: - open5gsIntegration: false + open5gsIntegration: false sbi: - - addr: 0.0.0.0 - port: 7778 + - addr: 127.0.0.22 + port: 7777 applicationServers: - canonicalHostname: localhost urlPathPrefixFormat: /m4d/provisioning-session-{provisioningSessionId}/ m3Port: 7777 - # The following parameters are only needed until M1 is implemented. - certificate: ../../examples/Certificates.json - contentHostingConfiguration: ../../examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest.json + certificateManager: ./certmgr + serverResponseCacheControl: + - maxAge: 61 + m1ProvisioningSessions: 62 + m1ContentHostingConfigurations: 63 + m1ServerCertificates: 65 + m1ContentProtocols: 86400 + m5ServiceAccessInformation: 64 + # The following parameters are only needed for MVP#2 and will be automated + # in future. + certificate: ../../examples/Certificates.json + contentHostingConfiguration: ../../examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_http_and_https.json # # nrf: # diff --git a/src/5gmsaf/utilities.c b/src/5gmsaf/utilities.c index 7b3e12b..167c444 100644 --- a/src/5gmsaf/utilities.c +++ b/src/5gmsaf/utilities.c @@ -17,6 +17,21 @@ program. If this file is missing then the license can be retrieved from #include #include "utilities.h" +void without_spaces(char *return_str, const char *in_str) +{ + while (*in_str != '\0') + { + if(!isspace(*in_str)) + { + *return_str = *in_str; + return_str++; + } + in_str++; + } + *return_str = '\0'; +} + + time_t str_to_time(char *str_time) { static time_t time; diff --git a/src/5gmsaf/utilities.h b/src/5gmsaf/utilities.h index 2039af2..1e987a8 100644 --- a/src/5gmsaf/utilities.h +++ b/src/5gmsaf/utilities.h @@ -33,6 +33,7 @@ extern uint16_t ascii_to_uint16(const char *str); extern int str_match(const char *line, const char *word_to_find); extern char *get_time(time_t time_epoch); extern time_t str_to_time(char *str_time); +extern void without_spaces(char *return_str, const char *in_str); #ifdef __cplusplus } From 309a5bf3ad6349de09ca61425c3c6135dcec7777 Mon Sep 17 00:00:00 2001 From: David Waring Date: Fri, 3 Mar 2023 17:35:43 +0000 Subject: [PATCH 15/48] Bug fixes and rework certificates management --- .gitignore | 2 + meson.build | 1 + src/5gmsaf/application-server-context.c | 279 +- src/5gmsaf/certmgr | 435 --- src/5gmsaf/certmgr.c | 270 +- src/5gmsaf/certmgr.h | 29 +- src/5gmsaf/context.c | 136 +- src/5gmsaf/context.h | 7 +- src/5gmsaf/hash.c | 8 +- src/5gmsaf/hash.h | 2 +- src/5gmsaf/headers.c | 185 ++ src/5gmsaf/headers.h | 57 + src/5gmsaf/meson.build | 29 +- src/5gmsaf/msaf-sm.c | 2935 +++++++++--------- src/5gmsaf/{msaf.yaml => msaf.yaml.in} | 16 +- src/5gmsaf/provisioning-session.c | 126 +- src/5gmsaf/utilities.c | 36 +- src/5gmsaf/utilities.h | 29 +- tools/bash/certmgr | 434 +++ tools/meson.build | 44 + tools/python3/lib/rt_m1_client/client.py | 622 ++++ tools/python3/lib/rt_m1_client/exceptions.py | 113 + tools/python3/lib/rt_m1_client/types.py | 317 ++ tools/python3/m1_client_cli.py | 87 + tools/python3/pylint.rc | 615 ++++ 25 files changed, 4277 insertions(+), 2537 deletions(-) create mode 100644 .gitignore delete mode 100755 src/5gmsaf/certmgr create mode 100644 src/5gmsaf/headers.c create mode 100644 src/5gmsaf/headers.h rename src/5gmsaf/{msaf.yaml => msaf.yaml.in} (91%) create mode 100755 tools/bash/certmgr create mode 100644 tools/meson.build create mode 100644 tools/python3/lib/rt_m1_client/client.py create mode 100644 tools/python3/lib/rt_m1_client/exceptions.py create mode 100644 tools/python3/lib/rt_m1_client/types.py create mode 100755 tools/python3/m1_client_cli.py create mode 100644 tools/python3/pylint.rc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d35cb3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__ +*.pyc diff --git a/meson.build b/meson.build index 4969880..b4eb904 100644 --- a/meson.build +++ b/meson.build @@ -22,4 +22,5 @@ fiveg_api_release = '17' sh_cmd = find_program('sh') patch_open5gs_result = run_command([sh_cmd, '-c', '"$MESON_SOURCE_ROOT/subprojects/patch_open5gs.sh" open5gs'], check: true, capture: false) open5gs_project=subproject('open5gs',required:true) +subdir('tools') subdir('src') diff --git a/src/5gmsaf/application-server-context.c b/src/5gmsaf/application-server-context.c index 1bbaccd..75e2ebe 100644 --- a/src/5gmsaf/application-server-context.c +++ b/src/5gmsaf/application-server-context.c @@ -156,103 +156,103 @@ void next_action_for_application_server(msaf_application_server_state_node_t *as ogs_assert(as_state); if (as_state->current_certificates == NULL) { - m3_client_as_state_requests(as_state, NULL, NULL, NULL, (char *)OGS_SBI_HTTP_METHOD_GET, "certificates"); + m3_client_as_state_requests(as_state, NULL, NULL, NULL, (char *)OGS_SBI_HTTP_METHOD_GET, "certificates"); } else if (as_state->current_content_hosting_configurations == NULL) { - m3_client_as_state_requests(as_state, NULL, NULL, NULL, (char *)OGS_SBI_HTTP_METHOD_GET, "content-hosting-configurations"); + m3_client_as_state_requests(as_state, NULL, NULL, NULL, (char *)OGS_SBI_HTTP_METHOD_GET, "content-hosting-configurations"); } else if (ogs_list_first(&as_state->upload_certificates) != NULL) { - const char *upload_cert_filename; - char *upload_cert_id; - char *provisioning_session; - char *cert_id; - char *data; - char *component; - resource_id_node_t *cert_id_node; - - resource_id_node_t *upload_cert = ogs_list_first(&as_state->upload_certificates); - ogs_list_for_each(as_state->current_certificates, cert_id_node) { - if (!strcmp(cert_id_node->state, upload_cert->state)) { - break; + const char *upload_cert_filename; + char *upload_cert_id; + char *provisioning_session; + char *cert_id; + char *data; + char *component; + resource_id_node_t *cert_id_node; + + resource_id_node_t *upload_cert = ogs_list_first(&as_state->upload_certificates); + ogs_list_for_each(as_state->current_certificates, cert_id_node) { + if (!strcmp(cert_id_node->state, upload_cert->state)) { + break; + } } - } - upload_cert_id = ogs_strdup(upload_cert->state); - provisioning_session = strtok_r(upload_cert_id,":",&cert_id); - upload_cert_filename = msaf_get_certificate_filename(provisioning_session, cert_id); - data = read_file(upload_cert_filename); - component = ogs_msprintf("certificates/%s:%s", provisioning_session, cert_id); - - if (cert_id_node) { - ogs_debug("M3 client: Sending PUT method to Application Server [%s] for Certificate: [%s]", as_state->application_server->canonicalHostname, upload_cert->state); - m3_client_as_state_requests(as_state, NULL, "application/x-pem-file", data, (char *)OGS_SBI_HTTP_METHOD_PUT, component); - free(data); - } else { - ogs_debug("M3 client: Sending POST method to Application Server [%s]for Certificate: [%s]", as_state->application_server->canonicalHostname, upload_cert->state); - m3_client_as_state_requests(as_state, NULL, "application/x-pem-file", data, (char *)OGS_SBI_HTTP_METHOD_POST, component); - free(data); - } - ogs_free(component); - ogs_free(upload_cert_id); + upload_cert_id = ogs_strdup(upload_cert->state); + provisioning_session = strtok_r(upload_cert_id,":",&cert_id); + upload_cert_filename = msaf_get_certificate_filename(provisioning_session, cert_id); + data = read_file(upload_cert_filename); + component = ogs_msprintf("certificates/%s:%s", provisioning_session, cert_id); + + if (cert_id_node) { + ogs_debug("M3 client: Sending PUT method to Application Server [%s] for Certificate: [%s]", as_state->application_server->canonicalHostname, upload_cert->state); + m3_client_as_state_requests(as_state, NULL, "application/x-pem-file", data, (char *)OGS_SBI_HTTP_METHOD_PUT, component); + free(data); + } else { + ogs_debug("M3 client: Sending POST method to Application Server [%s]for Certificate: [%s]", as_state->application_server->canonicalHostname, upload_cert->state); + m3_client_as_state_requests(as_state, NULL, "application/x-pem-file", data, (char *)OGS_SBI_HTTP_METHOD_POST, component); + free(data); + } + ogs_free(component); + ogs_free(upload_cert_id); } else if (ogs_list_first(&as_state->upload_content_hosting_configurations) != NULL) { - msaf_provisioning_session_t *provisioning_session; - OpenAPI_content_hosting_configuration_t *chc_with_af_unique_cert_id; - char *data; - char *component; - resource_id_node_t *chc_id_node; - cJSON *json; - - resource_id_node_t *upload_chc = ogs_list_first(&as_state->upload_content_hosting_configurations); - ogs_list_for_each(as_state->current_content_hosting_configurations, chc_id_node) { - if (!strcmp(chc_id_node->state, upload_chc->state)) { - break; + msaf_provisioning_session_t *provisioning_session; + OpenAPI_content_hosting_configuration_t *chc_with_af_unique_cert_id; + char *data; + char *component; + resource_id_node_t *chc_id_node; + cJSON *json; + + resource_id_node_t *upload_chc = ogs_list_first(&as_state->upload_content_hosting_configurations); + ogs_list_for_each(as_state->current_content_hosting_configurations, chc_id_node) { + if (!strcmp(chc_id_node->state, upload_chc->state)) { + break; + } } - } - provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(upload_chc->state); + provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(upload_chc->state); - chc_with_af_unique_cert_id = msaf_content_hosting_configuration_with_af_unique_cert_id(provisioning_session); + chc_with_af_unique_cert_id = msaf_content_hosting_configuration_with_af_unique_cert_id(provisioning_session); - json = OpenAPI_content_hosting_configuration_convertToJSON(chc_with_af_unique_cert_id); - data = cJSON_Print(json); + json = OpenAPI_content_hosting_configuration_convertToJSON(chc_with_af_unique_cert_id); + data = cJSON_Print(json); - component = ogs_msprintf("content-hosting-configurations/%s", upload_chc->state); + component = ogs_msprintf("content-hosting-configurations/%s", upload_chc->state); - if (chc_id_node) { - ogs_debug("M3 client: Sending PUT method to Application Server [%s] for Content Hosting Configuration: [%s]", as_state->application_server->canonicalHostname, upload_chc->state); - m3_client_as_state_requests(as_state, NULL, "application/json", data, (char *)OGS_SBI_HTTP_METHOD_PUT, component); - } else { - ogs_debug("M3 client: Sending POST method to Application Server [%s] for Content Hosting Configuration: [%s]", as_state->application_server->canonicalHostname, upload_chc->state); - m3_client_as_state_requests(as_state, NULL, "application/json", data, (char *)OGS_SBI_HTTP_METHOD_POST, component); - } - if (chc_with_af_unique_cert_id) OpenAPI_content_hosting_configuration_free(chc_with_af_unique_cert_id); - ogs_free(component); - cJSON_Delete(json); + if (chc_id_node) { + ogs_debug("M3 client: Sending PUT method to Application Server [%s] for Content Hosting Configuration: [%s]", as_state->application_server->canonicalHostname, upload_chc->state); + m3_client_as_state_requests(as_state, NULL, "application/json", data, (char *)OGS_SBI_HTTP_METHOD_PUT, component); + } else { + ogs_debug("M3 client: Sending POST method to Application Server [%s] for Content Hosting Configuration: [%s]", as_state->application_server->canonicalHostname, upload_chc->state); + m3_client_as_state_requests(as_state, NULL, "application/json", data, (char *)OGS_SBI_HTTP_METHOD_POST, component); + } + if (chc_with_af_unique_cert_id) OpenAPI_content_hosting_configuration_free(chc_with_af_unique_cert_id); + ogs_free(component); + cJSON_Delete(json); } else if (ogs_list_first(&as_state->delete_content_hosting_configurations) != NULL) { - char *component; - resource_id_node_t *delete_chc = ogs_list_first(&as_state->delete_content_hosting_configurations); - ogs_debug("M3 client: Sending DELETE method for Content Hosting Configuration [%s] to the Application Server [%s]", delete_chc->state, as_state->application_server->canonicalHostname); - component = ogs_msprintf("content-hosting-configurations/%s", delete_chc->state); - m3_client_as_state_requests(as_state, NULL, NULL, NULL, (char *)OGS_SBI_HTTP_METHOD_DELETE, component); - ogs_free(component); + char *component; + resource_id_node_t *delete_chc = ogs_list_first(&as_state->delete_content_hosting_configurations); + ogs_debug("M3 client: Sending DELETE method for Content Hosting Configuration [%s] to the Application Server [%s]", delete_chc->state, as_state->application_server->canonicalHostname); + component = ogs_msprintf("content-hosting-configurations/%s", delete_chc->state); + m3_client_as_state_requests(as_state, NULL, NULL, NULL, (char *)OGS_SBI_HTTP_METHOD_DELETE, component); + ogs_free(component); } else if (ogs_list_first(&as_state->delete_certificates) != NULL) { - char *component; - resource_id_node_t *delete_cert = ogs_list_first(&as_state->delete_certificates); - ogs_debug("M3 client: Sending DELETE method for certificate [%s] to the Application Server [%s]", delete_cert->state, as_state->application_server->canonicalHostname); - component = ogs_msprintf("certificates/%s", delete_cert->state); - m3_client_as_state_requests(as_state, NULL, NULL, NULL, (char *)OGS_SBI_HTTP_METHOD_DELETE, component); - ogs_free(component); + char *component; + resource_id_node_t *delete_cert = ogs_list_first(&as_state->delete_certificates); + ogs_debug("M3 client: Sending DELETE method for certificate [%s] to the Application Server [%s]", delete_cert->state, as_state->application_server->canonicalHostname); + component = ogs_msprintf("certificates/%s", delete_cert->state); + m3_client_as_state_requests(as_state, NULL, NULL, NULL, (char *)OGS_SBI_HTTP_METHOD_DELETE, component); + ogs_free(component); } else if(ogs_list_first(&as_state->purge_content_hosting_cache) != NULL){ purge_resource_id_node_t *purge_chc = ogs_list_first(&as_state->purge_content_hosting_cache); ogs_assert(purge_chc); ogs_assert(purge_chc->provisioning_session_id); - const char *component = ogs_msprintf("content-hosting-configurations/%s/purge", purge_chc->provisioning_session_id); + char *component = ogs_msprintf("content-hosting-configurations/%s/purge", purge_chc->provisioning_session_id); if(purge_chc->purge_regex) { - ogs_debug("M3 client: Sending cache purge operation for resource [%s] to the Application Server", purge_chc->provisioning_session_id); - m3_client_as_state_requests(as_state, purge_chc, "application/x-www-form-urlencoded", purge_chc->purge_regex, (char *)OGS_SBI_HTTP_METHOD_POST, component); + ogs_debug("M3 client: Sending cache purge operation for resource [%s] to the Application Server", purge_chc->provisioning_session_id); + m3_client_as_state_requests(as_state, purge_chc, "application/x-www-form-urlencoded", purge_chc->purge_regex, OGS_SBI_HTTP_METHOD_POST, component); } else { - ogs_debug("M3 client: Sending Purge operation for cache [%s] to the Application Server", purge_chc->provisioning_session_id); - m3_client_as_state_requests(as_state, purge_chc, "application/x-www-form-urlencoded", NULL, (char *)OGS_SBI_HTTP_METHOD_POST, component); + ogs_debug("M3 client: Sending Purge operation for cache [%s] to the Application Server", purge_chc->provisioning_session_id); + m3_client_as_state_requests(as_state, purge_chc, "application/x-www-form-urlencoded", NULL, OGS_SBI_HTTP_METHOD_POST, component); } ogs_free(component); @@ -306,7 +306,7 @@ static void msaf_application_server_remove(msaf_application_server_node_t *msaf_ ogs_free(msaf_as); } -static ogs_sbi_client_t * + static ogs_sbi_client_t * msaf_m3_client_init(const char *hostname, int port) { int rv; @@ -330,71 +330,74 @@ msaf_m3_client_init(const char *hostname, int port) return client; } -static int + static int m3_client_as_state_requests(msaf_application_server_state_node_t *as_state, - purge_resource_id_node_t *purge_node, - const char *type, const char *data, const char *method, - const char *component) + purge_resource_id_node_t *purge_node, + const char *type, const char *data, const char *method, + const char *component) { - ogs_sbi_request_t *request; - - request = ogs_sbi_request_new(); - request->h.method = ogs_strdup(method); - request->h.uri = ogs_msprintf("http://%s:%i/3gpp-m3/v1/%s", - as_state->application_server->canonicalHostname, - as_state->application_server->m3Port, component); - request->h.api.version = ogs_strdup("v1"); - if (data) { - request->http.content = ogs_strdup(data); - request->http.content_length = strlen(data); - } - if (type) - ogs_sbi_header_set(request->http.headers, "Content-Type", type); - - if (as_state->client == NULL) { - as_state->client = msaf_m3_client_init( - as_state->application_server->canonicalHostname, - as_state->application_server->m3Port); - } - client_request_info_t *request_info = ogs_calloc(1, sizeof(client_request_info_t)); - request_info->as_state = as_state; - request_info->purge_node = purge_node; - - ogs_sbi_client_send_request(as_state->client, client_notify_cb, request, request_info); - - ogs_sbi_request_free(request); - - return 1; + ogs_sbi_request_t *request; + + request = ogs_sbi_request_new(); + request->h.method = ogs_strdup(method); + request->h.uri = ogs_msprintf("http://%s:%i/3gpp-m3/v1/%s", + as_state->application_server->canonicalHostname, + as_state->application_server->m3Port, component); + request->h.api.version = ogs_strdup("v1"); + if (data) { + request->http.content = ogs_strdup(data); + request->http.content_length = strlen(data); + } + if (type) + ogs_sbi_header_set(request->http.headers, "Content-Type", type); + + if (as_state->client == NULL) { + as_state->client = msaf_m3_client_init( + as_state->application_server->canonicalHostname, + as_state->application_server->m3Port); + } + client_request_info_t *request_info = ogs_calloc(1, sizeof(client_request_info_t)); + request_info->as_state = as_state; + request_info->purge_node = purge_node; + + ogs_sbi_client_send_request(as_state->client, client_notify_cb, request, request_info); + + ogs_sbi_request_free(request); + + return 1; } -static int + static int client_notify_cb(int status, ogs_sbi_response_t *response, void *data) { - int rv; - client_request_info_t *client_request_info = data; - msaf_event_t *event; - - if (status != OGS_OK) { - ogs_log_message( - status == OGS_DONE ? OGS_LOG_DEBUG : OGS_LOG_WARN, 0, - "client_notify_cb() failed [%d]", status); - return OGS_ERROR; - } - - ogs_assert(response); - - event = (msaf_event_t*)ogs_event_new(OGS_EVENT_SBI_CLIENT); - event->h.sbi.response = response; - event->application_server_state = client_request_info->as_state; - event->purge_node = client_request_info->purge_node; - rv = ogs_queue_push(ogs_app()->queue, event); - if (rv !=OGS_OK) { - ogs_error("OGS Queue Push failed %d", rv); - ogs_sbi_response_free(response); - ogs_event_free(event); - return OGS_ERROR; - } - if (client_request_info->purge_node == NULL) ogs_free(client_request_info->purge_node); - ogs_free(client_request_info); - return OGS_OK; + int rv; + client_request_info_t *client_request_info = data; + msaf_event_t *event; + + if (status != OGS_OK) { + ogs_log_message( + status == OGS_DONE ? OGS_LOG_DEBUG : OGS_LOG_WARN, 0, + "client_notify_cb() failed [%d]", status); + return OGS_ERROR; + } + + ogs_assert(response); + + event = (msaf_event_t*)ogs_event_new(OGS_EVENT_SBI_CLIENT); + event->h.sbi.response = response; + event->application_server_state = client_request_info->as_state; + event->purge_node = client_request_info->purge_node; + rv = ogs_queue_push(ogs_app()->queue, event); + if (rv !=OGS_OK) { + ogs_error("OGS Queue Push failed %d", rv); + ogs_sbi_response_free(response); + ogs_event_free(event); + return OGS_ERROR; + } + if (client_request_info->purge_node == NULL) ogs_free(client_request_info->purge_node); + ogs_free(client_request_info); + return OGS_OK; } + +/* vim:ts=8:sts=4:sw=4:expandtab: +*/ diff --git a/src/5gmsaf/certmgr b/src/5gmsaf/certmgr deleted file mode 100755 index 55b5d18..0000000 --- a/src/5gmsaf/certmgr +++ /dev/null @@ -1,435 +0,0 @@ -#!/bin/bash -# -# 5G-MAG Reference Tools: Certificate Management script -# ====================================================== -# -# For full license terms please see the LICENSE file distributed with this -# program. If this file is missing then the license can be retrieved from -# https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view -# -# This script will use wget and git to download the openapi-generator-cli tool -# and a specified branch of the 5G APIs. It will then create a set of bindings -# in a specified output language. -# - -# Save location of this script and the name it was called by -scriptname=`basename "$0"` -scriptdir=`dirname "$0"` -scriptdir=`cd "$scriptdir"; pwd` - -# Variables -default_cert_op= -cert_operation= -cert_store="@cert_path@" -common_name= -server_certificate_resource_id= -cert_status= -cert_subject= -cache_control_max_age=70 - -# Parse command line arguments -ARGS=`getopt -n "$scriptname" -o 'c:h' -l 'cert-operation:,help' -s sh -- "$@"` - -print_syntax() { - echo "Syntax: $scriptname [-h] -c " -} - -if [ $? -ne 0 ]; then - print_syntax >&2 - exit 1 -fi - -print_help() { - cat <&2 - print_syntax >&2 - exit 1 - ;; - esac -done - -if [ $# -gt 0 ]; then - echo "Error: Command line argument \"$1\" unexpected" >&2 - print_syntax >&2 - exit 1 -fi - -if [ -z "$CERTOPS" ]; then - echo 'Error: Required command line parameter are missing' >&2 - print_syntax >&2 - exit 1 -fi - -cert_store_create() { - if [ ! -d "$cert_store/csrs" ]; then - mkdir -p $cert_store/csrs - fi - if [ ! -d "$cert_store/private" ]; then - mkdir -p $cert_store/private - fi - - if [ ! -d "$cert_store/public" ]; then - mkdir -p $cert_store/public - fi - -} - -cert_store_check() { - if [ -f "$cert_store/csrs/$server_certificate_resource_id.pem" ]; then - echo "CSR for Server Certificate Resource $server_certificate_resource_id exists already" - cat "$cert_store/csrs/$server_certificate_resource_id.pem" - exit 3 - fi - - if [ -f "$cert_store/public/$server_certificate_resource_id.pem" ]; then - echo "Certificate for Server Certificate Resource $server_certificate_resource_id exists already" - cat "$cert_store/public/$server_certificate_resource_id.pem" - exit 3 - fi -} - -ca_cert_check() { - - if ! [[ ( -f "$cert_store/private/ca.key" ) && ( -f "$cert_store/public/ca.crt" ) ]]; then - - # CA self certificate - openssl req -new -nodes -x509 -days 90 -newkey rsa:2048 -keyout "$cert_store/private/ca.key" -out "$cert_store/public/ca.crt" -subj "/C=GB/L=London/CN=$common_name" -addext "subjectAltName=DNS:$common_name" > /dev/null 2>&1 - fi -} - -new_csr() { - - cert_store_check >&2 - - openssl req -new -newkey rsa:2048 -batch -nodes -keyout "$cert_store/private/$server_certificate_resource_id.pem" -out "$cert_store/csrs/$server_certificate_resource_id.pem" -subj "/C=GB/L=London/CN=$common_name" -addext "subjectAltName=DNS:$common_name" > /dev/null 2>&1 - #cat "$cert_store/csrs/$server_certificate_resource_id.pem" - ts=`stat -c '%Y' "$cert_store/csrs/$server_certificate_resource_id.pem"` - timestamp=`TZ=GMT date --date=@$ts +'%a, %d %b %Y %H:%M:%S %Z'` - hashsum=($(sha256sum "$cert_store/csrs/$server_certificate_resource_id.pem")) - cert=`cat $cert_store/csrs/$server_certificate_resource_id.pem` - echo -e "Last-Modified: $timestamp\nETag: $hashsum\nCache-Control: max-age= $cache_control_max_age\n$cert" - exit 0 - -} - -new_cert() { - - cert_store_check >&2 - ca_cert_check >&2 - - # Generate server cert to be signed - openssl req -new -newkey rsa:2048 -batch -nodes -keyout "$cert_store/private/$server_certificate_resource_id.pem" -out "$cert_store/csrs/$server_certificate_resource_id.pem" -subj "/C=GB/L=London/CN=$common_name" -addext "subjectAltName=DNS:$common_name" > /dev/null 2>&1 - - openssl x509 -req -CA "$cert_store/public/ca.crt" -CAkey "$cert_store/private/ca.key" -CAcreateserial -in "$cert_store/csrs/$server_certificate_resource_id.pem" -out "$cert_store/public/$server_certificate_resource_id.pem" -days 90 > /dev/null 2>&1 - - ts=`stat -c '%Y' "$cert_store/public/$server_certificate_resource_id.pem"` - timestamp=`TZ=GMT date --date=@$ts +'%a, %d %b %Y %H:%M:%S %Z'` - hashsum=($(sha256sum "$cert_store/public/$server_certificate_resource_id.pem")) - - cert=`cat "$cert_store/public/$server_certificate_resource_id.pem"` - echo -e "Last-Modified: $timestamp\nETag: $hashsum\nCache-Control: max-age= $cache_control_max_age\n$cert" - exit 0 -} - -public_cert_get() { - - if ([ -f "$cert_store/csrs/$server_certificate_resource_id.pem" ] && ! [ -f "$cert_store/public/$server_certificate_resource_id.pem" ]); then - echo "Public Certificate for $server_certificate_resource_id not yet available." - exit 8 - fi - - if [ ! -f "$cert_store/public/$server_certificate_resource_id.pem" ]; then - echo "Certificate for $server_certificate_resource_id not found" - exit 4 - fi - - # cat $cert_store/public/$server_certificate_resource_id.pem $cert_store/public/ca.crt - - ts=`stat -c '%Y' "$cert_store/public/$server_certificate_resource_id.pem"` - timestamp=`TZ=GMT date --date=@$ts +'%a, %d %b %Y %H:%M:%S %Z'` - hashsum=($(sha256sum "$cert_store/public/$server_certificate_resource_id.pem")) - cert=`cat $cert_store/public/$server_certificate_resource_id.pem` - echo -e "Last-Modified: $timestamp\nETag: $hashsum\nCache-Control: max-age= $cache_control_max_age\n$cert" - - exit 0 -} - -server_cert_get() { - - if ( ! ( [ -f "$cert_store/public/$server_certificate_resource_id.pem" ] && [ -f "$cert_store/private/$server_certificate_resource_id.pem" ] )); then - echo "Credentials for $server_certificate_resource_id not yet available." - exit 8 - fi - - - ts=`stat -c '%Y' "$cert_store/public/$server_certificate_resource_id.pem"` - timestamp=`TZ=GMT date --date=@$ts +'%a, %d %b %Y %H:%M:%S %Z'` - hashsum=($(sha256sum "$cert_store/public/$server_certificate_resource_id.pem")) - cert=`cat $cert_store/public/$server_certificate_resource_id.pem $cert_store/private/$server_certificate_resource_id.pem` - echo -e "Last-Modified: $timestamp\nEtag: $hashsum\nMax-age: $cache_control_max_age\n$cert" - exit 0 -} - -cert_set() { -< "$cert_store/public/$server_certificate_resource_id.pem" - exit 0 - - elif [ -f "$cert_store/public/$server_certificate_resource_id.pem" ]; then - echo "Certificate already exists for $server_certificate_resource_id." - exit 3 - - elif ! [ -f "$cert_store/csrs/$server_certificate_resource_id.pem" ]; then - echo "No CSR issued: $server_certificate_resource_id." - exit 4 - fi - -} - -cert_expiry_check() { - if (openssl x509 -checkend 86400 -noout -in "$cert_store/public/$server_certificate_resource_id.pem" > /dev/null 2>&1) ; then - cert_status= - else - cert_status="Expired or will expire within 24 hours" - fi -} - -cert_list() { - if ( [ -f "$cert_store/private/$server_certificate_resource_id.pem" ] && ! [ -f "$cert_store/public/$server_certificate_resource_id.pem" ] ); then - cert_status="Awaiting" - cert_subject= - printf '%s\t%s\n' \ - "$server_certificate_resource_id" "$cert_status" - elif [ -f "$cert_store/public/$server_certificate_resource_id.pem" ]; then - cert_expiry_check >&2 - cert_subject=`openssl x509 -noout -subject -in $cert_store/public/$server_certificate_resource_id.pem` - printf '%s\t%s\t%s\n' \ - "$server_certificate_resource_id" "$cert_subject" "$cert_status" - fi -} - - -check_cert_revoke() { - - issuer=`openssl x509 -in $cert_store/public/$server_certificate_resource_id.pem -inform PEM -noout -issuer` - subject=`openssl x509 -in $cert_store/public/$server_certificate_resource_id.pem -inform PEM -noout -subject` - issuer="${issuer//issuer=/ }" - subject="${subject//subject=/ }" - if [ "$issuer" = "$subject" ]; then - can_be_revoked=0 - echo "Cannot revoke as $server_certificate_resource_id.pem is a self-signed certificate" - else - can_be_revoked=1 - fi - -} - -cert_revoke() { - check_cert_revoke >&2 - echo "in cert_revoke: $can_be_revoked" - if [ "$can_be_revoked" -eq "0" ] ; then - - echo "in cert_revoke:exit 2 $can_be_revoked" - exit 2 - fi - - openssl ca -revoke $cert_store/public/$server_certificate_resource_id.pem -keyfile "$cert_store/private/ca.key" -cert "$cert_store/public/ca.crt" - exit 0 - -} - -cert_delete() { - if ( [ -f "$cert_store/private/$server_certificate_resource_id.pem" ]); then - rm -f "$cert_store/private/$server_certificate_resource_id.pem" - fi - if ( [ -f "$cert_store/public/$server_certificate_resource_id.pem" ]); then - rm -f "$cert_store/public/$server_certificate_resource_id.pem" - fi - if ( [ -f "$cert_store/csrs/$server_certificate_resource_id.pem" ]); then - rm -f "$cert_store/csrs/$server_certificate_resource_id.pem" - fi -} - -certificate_delete() { - - check_cert_revoke >&2 - if [ "$can_be_revoked" -eq "0" ] ; then - echo "certificate delete: $can_be_revoked" - cert_delete >&2 - else - cert_revoke >&2 - cert_delete >&2 - fi - exit 0 -} - -<&2 - if ! [ $can_be_revoked ]; then - exit 2 - fi - exit 0 - -} - -cert_delete() { - - cert_revoke >&2 - if ( [ -f "$cert_store/private/$server_certificate_resource_id.pem" ]); then - rm -f "$cert_store/private/$server_certificate_resource_id.pem" - fi - - -} -revdel - - -parse_opts() { - - read -r -a cert_operation <<< "$CERTOPS" - if [ "$cert_operation" == "newcsr" ]; then - if [ ${#cert_operation[@]} -lt 3 ]; then - echo "$cert_operation: Not enough information to create a new csr" - exit 1 - fi - server_certificate_resource_id=${cert_operation[1]} - common_name=${cert_operation[2]} - new_csr >&2 - exit 1 - fi - - if [ "$cert_operation" == "newcert" ]; then - if [ ${#cert_operation[@]} -lt 3 ]; then - echo "$cert_operation: Not enough information to create a new certificate" - exit 1 - fi - server_certificate_resource_id=${cert_operation[1]} - common_name=${cert_operation[2]} - new_cert >&2 - fi - - if [ "$cert_operation" == "publiccert" ]; then - if [ ${#cert_operation[@]} -eq 2 ]; then - server_certificate_resource_id=${cert_operation[1]} - public_cert_get >&2 - else - echo "$cert_operation: has invalid options" - exit 1 - fi - fi - - if [ "$cert_operation" == "servercert" ]; then - if [ ${#cert_operation[@]} -eq 2 ]; then - server_certificate_resource_id=${cert_operation[1]} - server_cert_get >&2 - else - echo "$cert_operation: has invalid options" - exit 1 - fi - fi - - if [ "$cert_operation" == "setcert" ]; then - if [ ${#cert_operation[@]} -eq 2 ]; then - server_certificate_resource_id=${cert_operation[1]} - cert_set >&2 - else - echo "$cert_operation: has invalid options" - exit 1 - fi - fi - - if [ "$cert_operation" == "revoke" ]; then - if [ ${#cert_operation[@]} -eq 2 ]; then - server_certificate_resource_id=${cert_operation[1]} - cert_revoke >&2 - else - echo "$cert_operation: has invalid options" - exit 1 - fi - - fi - - if [ "$cert_operation" == "delete" ]; then - if [ ${#cert_operation[@]} -eq 2 ]; then - server_certificate_resource_id=${cert_operation[1]} - certificate_delete >&2 - else - echo "$cert_operation: has invalid options" - exit 1 - fi - - fi - - if [ "$cert_operation" == "list" ]; then - if [ ${#cert_operation[@]} -eq 2 ]; then - server_certificate_resource_id=${cert_operation[1]} - cert_list >&2 - else - for pem in $cert_store/public/*.pem; do - server_certificate_resource_id=`basename "${pem%.*}"` - cert_list >&2 - done - fi - fi -} - -cert_store_create >&2 -parse_opts >&2 - -exit 0 diff --git a/src/5gmsaf/certmgr.c b/src/5gmsaf/certmgr.c index bda297c..e1f2769 100644 --- a/src/5gmsaf/certmgr.c +++ b/src/5gmsaf/certmgr.c @@ -1,39 +1,39 @@ /* -License: 5G-MAG Public License (v1.0) -Author: Dev Audsin -Copyright: (C) 2022 British Broadcasting Corporation + * License: 5G-MAG Public License (v1.0) + * Author: Dev Audsin + * Copyright: (C) 2022 British Broadcasting Corporation + * + * For full license terms please see the LICENSE file distributed with this + * program. If this file is missing then the license can be retrieved from + * https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view + */ -For full license terms please see the LICENSE file distributed with this -program. If this file is missing then the license can be retrieved from -https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view -*/ +#include "ogs-core.h" -#include "certmgr.h" +#include "utilities.h" +#include "certmgr.h" #define MAX_CHILD_PROCESS 16 -#define OGS_ARG_MAX 256 static ogs_proc_t process[MAX_CHILD_PROCESS]; static int process_num = 0; -static msaf_certificate_t *msaf_certificate_populate(char *certid, char *cert, int out_return_code); +static msaf_certificate_t *msaf_certificate_populate(const char *certid, const char *cert, int out_return_code); -int server_cert_delete(char *certid) +int server_cert_delete(const char *certid) { const char *commandLine[OGS_ARG_MAX]; ogs_proc_t *current = NULL; FILE *out = NULL; char buf[OGS_HUGE_LEN]; int ret = 0, out_return_code = 0; - char *command; - char *rv = NULL; - command = ogs_msprintf("-c delete %s", certid); - - commandLine[0] = msaf_self()->config.certificateManager; - commandLine[1] = command; - commandLine[2] = NULL; + commandLine[0] = msaf_self()->config.certificateManager; + commandLine[1] = "-c"; + commandLine[2] = "delete"; + commandLine[3] = certid; + commandLine[4] = NULL; current = &process[process_num++]; ret = ogs_proc_create(commandLine, @@ -51,13 +51,12 @@ int server_cert_delete(char *certid) ogs_assert(ret == 0); ret = ogs_proc_destroy(current); ogs_assert(ret == 0); - ogs_free(command); return out_return_code; } -msaf_certificate_t *server_cert_retrieve(char *certid) -{ +msaf_certificate_t *server_cert_retrieve(const char *certid) +{ const char *commandLine[OGS_ARG_MAX]; ogs_proc_t *current = NULL; FILE *out = NULL; @@ -65,16 +64,14 @@ msaf_certificate_t *server_cert_retrieve(char *certid) char *cert = NULL; int ret = 0, out_return_code = 0; msaf_certificate_t *msaf_certificate = NULL; - char *command; - char *rv = NULL; size_t cert_size = 0; - size_t cert_reserved = 0; - - command = ogs_msprintf("-c publiccert %s", certid); + size_t cert_reserved = 0; commandLine[0] = msaf_self()->config.certificateManager; - commandLine[1] = command; - commandLine[2] = NULL; + commandLine[1] = "-c"; + commandLine[2] = "publiccert"; + commandLine[3] = certid; + commandLine[4] = NULL; current = &process[process_num++]; ret = ogs_proc_create(commandLine, @@ -93,14 +90,13 @@ msaf_certificate_t *server_cert_retrieve(char *certid) if(cert_size > cert_reserved - 1) { cert_reserved +=4096; cert = ogs_realloc(cert,cert_reserved); - } - strcat(cert,buf); - } + } + strcat(cert,buf); + } ret = ogs_proc_join(current, &out_return_code); ogs_assert(ret == 0); ret = ogs_proc_destroy(current); ogs_assert(ret == 0); - ogs_free(command); if(!out_return_code){ msaf_certificate = msaf_certificate_populate(certid, cert, out_return_code); ogs_assert(msaf_certificate); @@ -108,75 +104,68 @@ msaf_certificate_t *server_cert_retrieve(char *certid) return msaf_certificate; } -int server_cert_set(char *cert_id, char *cert) +int server_cert_set(const char *cert_id, const char *cert) { const char *commandLine[OGS_ARG_MAX]; ogs_proc_t *current = NULL; FILE *in = NULL; - char *bufin; - int ret = 0, out_return_code = 0, rv = 0; - char *operation; - - operation = ogs_msprintf("-c setcert %s", cert_id); + int ret = 0, out_return_code = 0; commandLine[0] = msaf_self()->config.certificateManager; - commandLine[1] = operation; - commandLine[2] = NULL; + commandLine[1] = "-c"; + commandLine[2] = "setcert"; + commandLine[3] = cert_id; + commandLine[4] = NULL; current = &process[process_num++]; - ret = ogs_proc_create(commandLine, + ret = ogs_proc_create(commandLine, ogs_proc_option_inherit_environment, current); ogs_assert(ret == 0); - + in = ogs_proc_stdin(current); ogs_assert(in); - if(cert) - { - fprintf(in, "%s", cert); + if (cert) { + fputs(cert, in); } ret = ogs_proc_join(current, &out_return_code); ogs_assert(ret == 0); ret = ogs_proc_destroy(current); ogs_assert(ret == 0); - ogs_free(operation); return out_return_code; } -msaf_certificate_t *server_cert_new(char *operation, char *operation_params) +msaf_certificate_t *server_cert_new(const char *operation, const char *operation_params) { const char *commandLine[OGS_ARG_MAX]; ogs_proc_t *current = NULL; FILE *out = NULL; - FILE *in = NULL; - char buf[4096]; + char buf[OGS_HUGE_LEN]; char *cert; int ret = 0, out_return_code = 0; char *canonical_domain_name; - char *certificate; msaf_certificate_t *msaf_certificate = NULL; size_t cert_size = 0; - size_t cert_reserved = 0; + size_t cert_reserved = 0; msaf_application_server_node_t *msaf_as = NULL; msaf_as = ogs_list_first(&msaf_self()->config.applicationServers_list); canonical_domain_name = msaf_as->canonicalHostname; ogs_uuid_t uuid; - char *command; char id[OGS_UUID_FORMATTED_LENGTH + 1]; - char *rv = NULL; ogs_uuid_get(&uuid); ogs_uuid_format(id, &uuid); - command = ogs_msprintf("-c %s %s %s", operation, id, canonical_domain_name); - commandLine[0] = msaf_self()->config.certificateManager; - commandLine[1] = command; - commandLine[2] = NULL; + commandLine[1] = "-c"; + commandLine[2] = operation; + commandLine[3] = id; + commandLine[4] = canonical_domain_name; + commandLine[5] = NULL; current = &process[process_num++]; ret = ogs_proc_create(commandLine, @@ -192,23 +181,23 @@ msaf_certificate_t *server_cert_new(char *operation, char *operation_params) while(fgets(buf, OGS_HUGE_LEN, out)) { cert_size += strlen (buf); - if(cert_size > cert_reserved - 1) { - cert_reserved =+ 4096; + if(cert_size > cert_reserved - 1) { + cert_reserved =+ 4096; cert = ogs_realloc(cert,cert_reserved); - } + } strcat(cert,buf); } ret = ogs_proc_join(current, &out_return_code); ogs_assert(ret == 0); ret = ogs_proc_destroy(current); ogs_assert(ret == 0); - ogs_free(command); - msaf_certificate = msaf_certificate_populate(id, cert, out_return_code); - ogs_assert(msaf_certificate); + msaf_certificate = msaf_certificate_populate(id, cert, out_return_code); + ogs_assert(msaf_certificate); + ogs_free(cert); return msaf_certificate; } -char *check_in_cert_list(char *canonical_domain_name) +char *check_in_cert_list(const char *canonical_domain_name) { const char *commandLine[OGS_ARG_MAX]; ogs_proc_t *current = NULL; @@ -218,16 +207,13 @@ char *check_in_cert_list(char *canonical_domain_name) char *certificate = NULL; char *cert_id; - char *operation; - - operation = ogs_msprintf("-c list"); - - commandLine[0] = msaf_self()->config.certificateManager; - commandLine[1] = operation; - commandLine[2] = NULL; + commandLine[0] = msaf_self()->config.certificateManager; + commandLine[1] = "-c"; + commandLine[2] = "list"; + commandLine[3] = NULL; current = &process[process_num++]; - ret = ogs_proc_create(commandLine, + ret = ogs_proc_create(commandLine, ogs_proc_option_combined_stdout_stderr| ogs_proc_option_inherit_environment, current); @@ -237,75 +223,93 @@ char *check_in_cert_list(char *canonical_domain_name) while(fgets(buf, OGS_HUGE_LEN, out)) { - if (str_match(buf, canonical_domain_name)) { - certificate = strtok_r(buf,"\t",&cert_id); - break; - } + ogs_debug("buf=\"%s\", canonical_domain_name=\"%s\"", buf, canonical_domain_name); + if (str_match(buf, canonical_domain_name)) { + certificate = strtok_r(buf,"\t",&cert_id); + ogs_debug("buf=\"%s\", certificate=\"%s\", cert_id=\"%s\"", buf, certificate, cert_id); + break; + } } ret = ogs_proc_join(current, &out_return_code); ogs_assert(ret == 0); ret = ogs_proc_destroy(current); ogs_assert(ret == 0); - ogs_free(operation); - return certificate; + + if (!certificate) return NULL; + + return ogs_strdup(certificate); } -static msaf_certificate_t *msaf_certificate_populate(char *certid, char *cert, int out_return_code) +static msaf_certificate_t *msaf_certificate_populate(const char *certid, const char *cert, int out_return_code) { - msaf_certificate_t *msaf_certificate = NULL; - char *token; - char *string; - char *key; - char *val; - char *value; - char *ptr; - char *populated_certificate; - msaf_certificate = ogs_calloc(1, sizeof(msaf_certificate_t)); - ogs_assert(msaf_certificate); - msaf_certificate->id = certid; - msaf_certificate->return_code = out_return_code; - populated_certificate = ogs_calloc(1, strlen(cert)); - ptr = string = ogs_strdup(cert); - while ((token = strsep(&string, "\n")) != NULL) - { - if(strstr(token, "Last-Modified:") || strstr(token, "ETag:") || strstr(token, "Cache-Control: max-age=")){ - key = strtok_r(token,":",&val); - ogs_info("key: %s, value: %s", key, val); - value = ogs_calloc(1, strlen(val)); - without_spaces(value, val); - ogs_assert(value); - if (!strcmp(key,"Last-Modified")){ - ogs_debug("key: %s, value: %s", key, value); - msaf_certificate->last_modified = str_to_time(value); - ogs_free(value); - } else if (!strcmp(key,"Cache-Control")){ - char *max_age_key; - char *max_age_value; - char *max_age = ogs_strdup(value); - max_age_key = strtok_r(max_age,"=",&max_age_value); - without_spaces(value, max_age_value); - ogs_debug("key: %s, value: %s", key, value); - if(!strcmp(value,"")){ - msaf_certificate->cache_control_max_age = 0; - } else { - msaf_certificate->cache_control_max_age = ascii_to_long(value); - } - ogs_free(max_age); - ogs_free(value); - } else if (!strcmp(key,"ETag")){ - ogs_debug("key: %s, value: %s", key, value); - msaf_certificate->server_certificate_hash = value; - } else { - ogs_debug("Unrecognised key: %s, value: %s", key, value); - } - - } else { - strcat(populated_certificate,token); - strcat(populated_certificate,"\n"); - } + msaf_certificate_t *msaf_certificate; + const char *line; + const char *eol; + const char *hdr_value; + static const char begin_marker[] = "-----BEGIN"; + static const char max_age_str[] = "max-age="; + + msaf_certificate = ogs_calloc(1, sizeof(msaf_certificate_t)); + ogs_assert(msaf_certificate); + + msaf_certificate->id = ogs_strdup(certid); + msaf_certificate->return_code = out_return_code; + + msaf_certificate->headers = nf_headers_new(); + ogs_assert(msaf_certificate->headers); + + line = cert; + while ((eol = strchr(line, '\n')) != NULL) { + const char *end_field; + /* Stop when we get to the certificate, key or CSR */ + if (strncmp(line, begin_marker, sizeof(begin_marker)-1) == 0) + break; + /* otherwise try and interpret as "Field: Value" */ + end_field = strchr(line, ':'); + if (end_field) { + char *field; + char *value; + const char *value_start; + const char *value_end; + field = ogs_strndup(line, end_field-line); + value_start = end_field+1; + while (*value_start && *value_start == ' ') value_start++; + value_end = eol-1; + while (value_end>value_start && *value_end == ' ') value_end--; + value = ogs_strndup(value_start, value_end-value_start+1); + nf_headers_set(msaf_certificate->headers, field, value); + ogs_free(field); + ogs_free(value); + } + line = eol+1; + } + + msaf_certificate->certificate = ogs_strdup(line); + + hdr_value = nf_headers_get(msaf_certificate->headers, "Last-Modified"); + if (hdr_value) { + msaf_certificate->last_modified = str_to_time(hdr_value); + } + + hdr_value = nf_headers_get(msaf_certificate->headers, "Cache-Control"); + if (hdr_value && strncmp(hdr_value, max_age_str, sizeof(max_age_str)-1)==0) { + msaf_certificate->cache_control_max_age = ascii_to_long(hdr_value+sizeof(max_age_str)-1); + } + + hdr_value = nf_headers_get(msaf_certificate->headers, "ETag"); + if (hdr_value) { + msaf_certificate->server_certificate_hash = ogs_strdup(hdr_value); } - msaf_certificate->certificate = populated_certificate; - ogs_free(ptr); - return msaf_certificate; + + return msaf_certificate; +} + +void msaf_certificate_free(msaf_certificate_t *cert) +{ + if (cert->headers) nf_headers_free(cert->headers); + if (cert->certificate) ogs_free(cert->certificate); + if (cert->server_certificate_hash) ogs_free(cert->server_certificate_hash); + if (cert->id) ogs_free(cert->id); + ogs_free(cert); } diff --git a/src/5gmsaf/certmgr.h b/src/5gmsaf/certmgr.h index 1532651..6ff9a2a 100644 --- a/src/5gmsaf/certmgr.h +++ b/src/5gmsaf/certmgr.h @@ -1,18 +1,18 @@ /* -License: 5G-MAG Public License (v1.0) -Author: Dev Audsin -Copyright: (C) 2022 British Broadcasting Corporation - -For full license terms please see the LICENSE file distributed with this -program. If this file is missing then the license can be retrieved from -https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view + * License: 5G-MAG Public License (v1.0) + * Author: Dev Audsin + * Copyright: (C) 2022 British Broadcasting Corporation + * + * For full license terms please see the LICENSE file distributed with this + * program. If this file is missing then the license can be retrieved from + * https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view */ #ifndef MSAF_CERT_MGR_H #define MSAF_CERT_MGR_H #include "context.h" - +#include "headers.h" #ifdef __cplusplus extern "C" { @@ -23,21 +23,22 @@ typedef struct msaf_certificate_s { char *certificate; time_t last_modified; char *server_certificate_hash; + nf_headers_t *headers; int cache_control_max_age; int return_code; } msaf_certificate_t; - typedef struct msaf_assigned_certificate_s { ogs_lnode_t node; char *certificate_id; } msaf_assigned_certificate_t; -extern msaf_certificate_t *server_cert_new(char *operation, char *operation_params); -extern int server_cert_set(char *cert_id, char *cert); -extern msaf_certificate_t *server_cert_retrieve(char *certid); -extern char *check_in_cert_list(char *canonical_domain_name); -extern int server_cert_delete(char *certid); +extern msaf_certificate_t *server_cert_new(const char *operation, const char *operation_params); +extern int server_cert_set(const char *cert_id, const char *cert); +extern msaf_certificate_t *server_cert_retrieve(const char *certid); +extern char *check_in_cert_list(const char *canonical_domain_name); +extern int server_cert_delete(const char *certid); +extern void msaf_certificate_free(msaf_certificate_t *cert); #ifdef __cplusplus } diff --git a/src/5gmsaf/context.c b/src/5gmsaf/context.c index 3f116d5..827a500 100644 --- a/src/5gmsaf/context.c +++ b/src/5gmsaf/context.c @@ -90,12 +90,6 @@ void msaf_context_final(void) ogs_hash_destroy(self->content_hosting_configuration_file_map); } - if(self->config.contentHostingConfiguration) - ogs_free(self->config.contentHostingConfiguration); - - if(self->config.certificate) - ogs_free(self->config.certificate); - if (self->config.server_response_cache_control) { ogs_free(self->config.server_response_cache_control); @@ -152,12 +146,8 @@ int msaf_context_parse_config(void) if (!strcmp(open5gs, "true")) { self->config.open5gsIntegration_flag = 1; } - } else if (!strcmp(msaf_key, "certificate")) { - self->config.certificate = rebase_path(ogs_app()->file, ogs_yaml_iter_value(&msaf_iter)); } else if (!strcmp(msaf_key, "certificateManager")) { self->config.certificateManager = ogs_strdup(ogs_yaml_iter_value(&msaf_iter)); - } else if (!strcmp(msaf_key, "contentHostingConfiguration")) { - self->config.contentHostingConfiguration = rebase_path(ogs_app()->file, ogs_yaml_iter_value(&msaf_iter)); } else if (!strcmp(msaf_key, "applicationServers")) { ogs_yaml_iter_t as_iter, as_array; ogs_yaml_iter_recurse(&msaf_iter, &as_array); @@ -203,8 +193,8 @@ int msaf_context_parse_config(void) int m1_provisioning_session_response_max_age = SERVER_RESPONSE_MAX_AGE; int m1_content_hosting_configurations_response_max_age = SERVER_RESPONSE_MAX_AGE; int m1_server_certificates_response_max_age = SERVER_RESPONSE_MAX_AGE; - int m1_content_protocols_response_max_age = M1_CONTENT_PROTOCOLS_RESPONSE_MAX_AGE; - int m5_service_access_information_response_max_age = SERVER_RESPONSE_MAX_AGE; + int m1_content_protocols_response_max_age = M1_CONTENT_PROTOCOLS_RESPONSE_MAX_AGE; + int m5_service_access_information_response_max_age = SERVER_RESPONSE_MAX_AGE; while (ogs_yaml_iter_next(&cc_iter)) { const char *cc_key = ogs_yaml_iter_key(&cc_iter); ogs_assert(cc_key); @@ -426,121 +416,6 @@ msaf_context_get_content_hosting_configuration_resource_identifier(const char *c /***** Private functions *****/ -static void msaf_context_delete_certificate(const char *resource_id) { - - msaf_application_server_state_node_t *as_state; - ogs_list_for_each(&self->application_server_states, as_state) { - resource_id_node_t *certificate, *next = NULL; - resource_id_node_t *upload_certificate, *next_node = NULL; - resource_id_node_t *delete_cert = NULL; - ogs_list_init(&as_state->delete_certificates); - - if (as_state->current_certificates) { - - char *current_cert_id; - char *provisioning_session; - char *cert_id; - - ogs_list_for_each_safe(as_state->current_certificates, next, certificate){ - - current_cert_id = ogs_strdup(certificate->state); - provisioning_session = strtok_r(current_cert_id,":",&cert_id); - - if(!strcmp(provisioning_session, resource_id)) - break; - - if(current_cert_id) - ogs_free(current_cert_id); - - } - - if(certificate) { - delete_cert = ogs_calloc(1, sizeof(resource_id_node_t)); - ogs_assert(delete_cert); - delete_cert->state = ogs_strdup(certificate->state); - ogs_list_add(&as_state->delete_certificates, delete_cert); - - //ogs_list_add(&as_state->delete_certificates, certificate); - } - - if(current_cert_id) - ogs_free(current_cert_id); - } - - { - char *upload_cert_id = NULL; - char *provisioning_session; - char *cert_id; - - ogs_list_for_each_safe(&as_state->upload_certificates, next_node, upload_certificate) { - - upload_cert_id = ogs_strdup(upload_certificate->state); - provisioning_session = strtok_r(upload_cert_id,":",&cert_id); - if(!strcmp(provisioning_session, resource_id)) - break; - } - - if (upload_certificate) { - - ogs_list_remove(&as_state->upload_certificates, upload_certificate); - - ogs_list_add(&as_state->delete_certificates, upload_certificate); - - } - - if (upload_cert_id) - ogs_free(upload_cert_id); - } - - //next_action_for_application_server(as_state); - - } -} - -static void msaf_context_delete_content_hosting_configuration(const char *resource_id) { - - msaf_application_server_state_node_t *as_state; - ogs_list_for_each(&self->application_server_states, as_state) { - - resource_id_node_t *content_hosting_configuration, *next = NULL; - resource_id_node_t *upload_content_hosting_configuration, *next_node = NULL; - resource_id_node_t *delete_chc = NULL; - - ogs_list_init(&as_state->delete_content_hosting_configurations); - - if (as_state->current_content_hosting_configurations) { - - ogs_list_for_each_safe(as_state->current_content_hosting_configurations, next, content_hosting_configuration){ - - if(!strcmp(content_hosting_configuration->state, resource_id)) - break; - } - if(content_hosting_configuration) { - - delete_chc = ogs_calloc(1, sizeof(resource_id_node_t)); - ogs_assert(delete_chc); - delete_chc->state = ogs_strdup(content_hosting_configuration->state); - ogs_list_add(&as_state->delete_content_hosting_configurations, delete_chc); - - } - } - - ogs_list_for_each_safe(&as_state->upload_content_hosting_configurations, next_node, upload_content_hosting_configuration){ - if(!strcmp(upload_content_hosting_configuration->state, resource_id)) - break; - } - if (upload_content_hosting_configuration) { - - ogs_list_remove(&as_state->upload_content_hosting_configurations, upload_content_hosting_configuration); - - ogs_list_add(&as_state->delete_content_hosting_configurations, upload_content_hosting_configuration); - - } - - next_action_for_application_server(as_state); - } -} - static void msaf_context_server_addr_remove_all() { msaf_context_server_addr_t *msaf_server_addr = NULL, *next = NULL; @@ -721,13 +596,6 @@ safe_ogs_free(void *memory) ogs_free(memory); } -ogs_hash_t * -msaf_context_content_hosting_configuration_file_map(char *provisioning_session_id) -{ - ogs_hash_set(self->content_hosting_configuration_file_map, ogs_strdup(self->config.contentHostingConfiguration), OGS_HASH_KEY_STRING, ogs_strdup(provisioning_session_id)); - return self->content_hosting_configuration_file_map; -} - static void msaf_context_server_addr_add(const char *server_addr) { msaf_context_server_addr_t *msaf_server_addr; msaf_server_addr = ogs_calloc(1, sizeof(msaf_context_server_addr_t)); diff --git a/src/5gmsaf/context.h b/src/5gmsaf/context.h index 1920759..50f2d59 100644 --- a/src/5gmsaf/context.h +++ b/src/5gmsaf/context.h @@ -11,6 +11,11 @@ program. If this file is missing then the license can be retrieved from #ifndef MSAF_CONTEXT_H #define MSAF_CONTEXT_H +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include #include #include #include @@ -43,8 +48,6 @@ typedef struct msaf_configuration_s { int open5gsIntegration_flag; ogs_list_t applicationServers_list; ogs_list_t server_addr_list; // Nodes for this list are of type msaf_sbi_addr_t * - char *contentHostingConfiguration; - char *certificate; char *certificateManager; msaf_server_response_cache_control_t *server_response_cache_control; int number_of_application_servers; diff --git a/src/5gmsaf/hash.c b/src/5gmsaf/hash.c index db3d09c..30e32cb 100644 --- a/src/5gmsaf/hash.c +++ b/src/5gmsaf/hash.c @@ -10,12 +10,14 @@ program. If this file is missing then the license can be retrieved from #include "hash.h" -char *calculate_hash(char *buf) { - const unsigned char *result = NULL; - size_t result_len = gnutls_hash_get_len(GNUTLS_DIG_SHA256); +const char *calculate_hash(const char *buf) { + unsigned char *result = NULL; + size_t result_len; gnutls_datum_t data; static char hash[1024]; size_t i; + + result_len = gnutls_hash_get_len(GNUTLS_DIG_SHA256); data.data = (unsigned char *)buf; data.size = strlen(buf); result = ogs_calloc(1, result_len); diff --git a/src/5gmsaf/hash.h b/src/5gmsaf/hash.h index 384f5b5..5fa7685 100644 --- a/src/5gmsaf/hash.h +++ b/src/5gmsaf/hash.h @@ -20,7 +20,7 @@ program. If this file is missing then the license can be retrieved from extern "C" { #endif -extern char *calculate_hash(char *buf); +extern const char *calculate_hash(const char *buf); #ifdef __cplusplus } diff --git a/src/5gmsaf/headers.c b/src/5gmsaf/headers.c new file mode 100644 index 0000000..e4d34da --- /dev/null +++ b/src/5gmsaf/headers.c @@ -0,0 +1,185 @@ +/* + * License: 5G-MAG Public License (v1.0) + * Author: David Waring + * Copyright: (C) 2023 British Broadcasting Corporation + * + * For full license terms please see the LICENSE file distributed with this + * program. If this file is missing then the license can be retrieved from + * https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view + */ + +#include "ogs-core.h" + +#include "headers.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* nf_headers_t methods */ +nf_headers_t *nf_headers_new() +{ + nf_headers_t *hdrs; + + hdrs = ogs_calloc(1, sizeof(nf_headers_t)); + hdrs->hdrs = ogs_hash_make(); + + return hdrs; +} + +static int headers_hash_do_free(void *rec, const void *key, int klen, const void *value) +{ + ogs_free((void*)value); + ogs_hash_set((ogs_hash_t*)rec, key, klen, NULL); + ogs_free((void*)key); + return 1; +} + +void nf_headers_free(nf_headers_t *headers) +{ + if (headers->hdrs) { + ogs_hash_do(headers_hash_do_free, headers->hdrs, headers->hdrs); + ogs_hash_destroy(headers->hdrs); + } + ogs_free(headers); +} + +const char *nf_headers_get(nf_headers_t *headers, const char *fieldname) +{ + nf_headers_iter_t *iter; + + iter = nf_headers_iter_find(headers, fieldname); + if (iter) { + const char *ret; + ret = nf_headers_iter_value(iter); + nf_headers_iter_free(iter); + return ret; + } + return NULL; +} + +int nf_headers_set(nf_headers_t *headers, const char *fieldname, const char *value) +{ + nf_headers_iter_t *iter; + iter = nf_headers_iter_find(headers, fieldname); + if (iter) { + ogs_hash_set(headers->hdrs, nf_headers_iter_fieldname(iter), OGS_HASH_KEY_STRING, NULL); + nf_headers_iter_free(iter); + } + ogs_hash_set(headers->hdrs, ogs_strdup(fieldname), OGS_HASH_KEY_STRING, ogs_strdup(value)); + return 1; +} + +int nf_headers_add(nf_headers_t *headers, const char *fieldname, const char *value) { + nf_headers_iter_t *iter; + iter = nf_headers_iter_find(headers, fieldname); + if (iter) { + char *new_value = ogs_msprintf("%s, %s", nf_headers_iter_value(iter), value); + ogs_hash_set(headers->hdrs, nf_headers_iter_fieldname(iter), OGS_HASH_KEY_STRING, new_value); + } else { + ogs_hash_set(headers->hdrs, ogs_strdup(fieldname), OGS_HASH_KEY_STRING, ogs_strdup(value)); + } + return 1; +} + +int nf_headers_delete(nf_headers_t *headers, const char *fieldname) +{ + nf_headers_iter_t *iter; + iter = nf_headers_iter_find(headers, fieldname); + if (iter) { + ogs_hash_set(headers->hdrs, nf_headers_iter_fieldname(iter), OGS_HASH_KEY_STRING, NULL); + return 1; + } + return 0; +} + +int nf_headers_clear(nf_headers_t *headers) +{ + ogs_hash_clear(headers->hdrs); + return 1; +} + +int nf_headers_count(nf_headers_t *headers) +{ + return ogs_hash_count(headers->hdrs); +} + +typedef struct hdrs_hash_do_data_s { + nf_headers_do_callback_fn_t *fn; + nf_headers_t *headers; + void *user_data; +} hdrs_hash_do_data_t; + +static int _hash_do_callback(void *rec, const void *key, int key_len, const void *value) +{ + hdrs_hash_do_data_t *data = (hdrs_hash_do_data_t*)rec; + + return data->fn((const char *)key, (const char *)value, data->user_data); +} + +int nf_headers_do(nf_headers_t *headers, nf_headers_do_callback_fn_t *fn, void *user_data) +{ + hdrs_hash_do_data_t data = {fn, headers, user_data}; + + return ogs_hash_do(_hash_do_callback, &data, headers->hdrs); +} + +/* Iterator for nf_headers_t */ +nf_headers_iter_t *nf_headers_iter_new(nf_headers_t *headers) +{ + nf_headers_iter_t *iter; + + iter = ogs_calloc(1, sizeof(nf_headers_iter_t)); + iter->ptr = ogs_hash_first(headers->hdrs); + if (!iter->ptr) { + ogs_free(iter); + return NULL; + } + return iter; +} + +nf_headers_iter_t *nf_headers_iter_find(nf_headers_t *headers, const char *fieldname) +{ + nf_headers_iter_t *iter; + + for (iter = nf_headers_iter_new(headers); iter; iter = nf_headers_iter_next(iter)) { + if (!strcasecmp(nf_headers_iter_fieldname(iter), fieldname)) { + return iter; + } + } + return NULL; +} + +nf_headers_iter_t *nf_headers_iter_next(nf_headers_iter_t *iter) +{ + iter->ptr = ogs_hash_next(iter->ptr); + if (!iter->ptr) { + ogs_free(iter); + return NULL; + } + return iter; +} + +const char *nf_headers_iter_fieldname(nf_headers_iter_t *iter) +{ + if (!iter) return NULL; + return (const char *)ogs_hash_this_key(iter->ptr); +} + +const char *nf_headers_iter_value(nf_headers_iter_t *iter) +{ + if (!iter) return NULL; + return (const char *)ogs_hash_this_val(iter->ptr); +} + +void nf_headers_iter_free(nf_headers_iter_t *iter) +{ + ogs_free(iter); +} + +#ifdef __cplusplus +} +#endif + +/* vim:ts=8:sts=4:sw=4:expandtab: + */ diff --git a/src/5gmsaf/headers.h b/src/5gmsaf/headers.h new file mode 100644 index 0000000..71da4bf --- /dev/null +++ b/src/5gmsaf/headers.h @@ -0,0 +1,57 @@ +/* + * License: 5G-MAG Public License (v1.0) + * Author: David Waring + * Copyright: (C) 2023 British Broadcasting Corporation + * + * For full license terms please see the LICENSE file distributed with this + * program. If this file is missing then the license can be retrieved from + * https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view + */ + +#ifndef NF_HEADERS_H +#define NF_HEADERS_H + +#include "ogs-core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct nf_headers_s { + ogs_hash_t *hdrs; +} nf_headers_t; + +typedef struct nf_headers_iter_s { + ogs_hash_index_t *ptr; +} nf_headers_iter_t; + +typedef int (nf_headers_do_callback_fn_t)(const char *fieldname, const char *value, void *data); + +/* nf_headers_t methods */ +extern nf_headers_t *nf_headers_new(); +extern void nf_headers_free(nf_headers_t *); + +extern const char *nf_headers_get(nf_headers_t *headers, const char *fieldname); +extern int nf_headers_set(nf_headers_t *headers, const char *fieldname, const char *value); +extern int nf_headers_add(nf_headers_t *headers, const char *fieldname, const char *value); +extern int nf_headers_delete(nf_headers_t *headers, const char *fieldname); + +extern int nf_headers_clear(nf_headers_t *headers); + +extern int nf_headers_count(nf_headers_t *headers); + +extern int nf_headers_do(nf_headers_t *headers, nf_headers_do_callback_fn_t *fn, void *data); + +/* Iterator for nf_headers_t */ +extern nf_headers_iter_t *nf_headers_iter_new(nf_headers_t *headers); +extern nf_headers_iter_t *nf_headers_iter_next(nf_headers_iter_t *); +extern const char *nf_headers_iter_fieldname(nf_headers_iter_t *); +extern const char *nf_headers_iter_value(nf_headers_iter_t *); +extern nf_headers_iter_t *nf_headers_iter_find(nf_headers_t *headers, const char *fieldname); +extern void nf_headers_iter_free(nf_headers_iter_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* NF_HEADERS_H */ diff --git a/src/5gmsaf/meson.build b/src/5gmsaf/meson.build index ca40ef0..d252496 100644 --- a/src/5gmsaf/meson.build +++ b/src/5gmsaf/meson.build @@ -30,6 +30,8 @@ libmsaf_dist_sources = files(''' certmgr.h hash.h hash.c + headers.c + headers.h response-cache-control.h response-cache-control.c provisioning-session.h @@ -200,13 +202,13 @@ content_hosting_discovery_protocols_conf = configuration_data() content_hosting_discovery_protocols_conf.set_quoted('CONTENT_PROTOCOLS_DISCOVERY_JSON', file_content) content_hosting_discovery_protocols_conf.set_quoted('CONTENT_PROTOCOLS_DISCOVERY_JSON_HASH', file_hash) content_hosting_discovery_protocols_conf.set('CONTENT_PROTOCOLS_DISCOVERY_JSON_TIME', file_time) -configure_file(output : 'ContentProtocolsDiscovery_body.h', configuration : content_hosting_discovery_protocols_conf) +libmsaf_gen_sources += [configure_file(output : 'ContentProtocolsDiscovery_body.h', configuration : content_hosting_discovery_protocols_conf)] version_conf = configuration_data() version_conf.set_quoted('MSAF_NAME', meson.project_name()) version_conf.set_quoted('MSAF_VERSION', meson.project_version()) version_conf.set_quoted('FIVEG_API_RELEASE', fiveg_api_release) -configure_file(output : 'msaf-version.h', configuration : version_conf) +libmsaf_gen_sources += [configure_file(output : 'msaf-version.h', configuration : version_conf)] libmsaf_sources = libmsaf_dist_sources + libmsaf_gen_sources @@ -240,26 +242,9 @@ executable('open5gs-msafd', install : true) meson.add_install_script(python3_exe, '-c', mkdir_p.format(open5gs_sysconfdir)) +conf_configuration = configuration_data() +conf_configuration.set('default-certmgr', get_option('prefix') / self_signed_certmgr_runtime) foreach conf_file : msaf_config_source - gen = configure_file(input : conf_file, copy : true, output : conf_file) + gen = configure_file(input : conf_file + '.in', configuration : conf_configuration, output : conf_file) meson.add_install_script(python3_exe, '-c', install_conf.format(gen, open5gs_sysconfdir)) endforeach - -cert_path = join_paths(meson.current_build_dir(), 'certificate') -mkdir_cert_result = run_command(['mkdir', '-p', cert_path], check: true, capture: false) - - -tools_path = join_paths(meson.current_build_dir(), 'tools') -mkdir_tools_result = run_command(['mkdir', '-p', tools_path], check: true, capture: false) - -cert_conf_data = configuration_data() -cert_conf_data.set('path', cert_path) -cert_mgr = configure_file(input : 'certmgr', - output : 'certmgr', - configuration : cert_conf_data) -meson.add_install_script(python3_exe, '-c', install_conf.format(cert_mgr, open5gs_sysconfdir)) - -cert_mgr_file = join_paths(meson.current_build_dir(), 'certmgr') - -mkdir_cert_mgr_result = run_command(['mv', cert_mgr_file, tools_path], check: true, capture: false) - diff --git a/src/5gmsaf/msaf-sm.c b/src/5gmsaf/msaf-sm.c index 102c9ca..5b8491b 100644 --- a/src/5gmsaf/msaf-sm.c +++ b/src/5gmsaf/msaf-sm.c @@ -16,6 +16,7 @@ #include "server.h" #include "response-cache-control.h" #include "msaf-version.h" +#include "ContentProtocolsDiscovery_body.h" #include "openapi/api/TS26512_M1_ProvisioningSessionsAPI-info.h" #include "openapi/api/TS26512_M1_ServerCertificatesProvisioningAPI-info.h" #include "openapi/api/TS26512_M1_ContentHostingProvisioningAPI-info.h" @@ -26,33 +27,39 @@ const nf_server_interface_metadata_t m1_provisioningsession_api_metadata = { -M1_PROVISIONINGSESSIONS_API_NAME, -M1_PROVISIONINGSESSIONS_API_VERSION}; + M1_PROVISIONINGSESSIONS_API_NAME, + M1_PROVISIONINGSESSIONS_API_VERSION +}; const nf_server_interface_metadata_t m1_contenthostingprovisioning_api_metadata = { -M1_CONTENTHOSTINGPROVISIONING_API_NAME, -M1_CONTENTHOSTINGPROVISIONING_API_VERSION}; + M1_CONTENTHOSTINGPROVISIONING_API_NAME, + M1_CONTENTHOSTINGPROVISIONING_API_VERSION +}; const nf_server_interface_metadata_t m1_contentprotocolsdiscovery_api_metadata = { -M1_CONTENTPROTOCOLSDISCOVERY_API_NAME, -M1_CONTENTPROTOCOLSDISCOVERY_API_VERSION}; + M1_CONTENTPROTOCOLSDISCOVERY_API_NAME, + M1_CONTENTPROTOCOLSDISCOVERY_API_VERSION +}; const nf_server_interface_metadata_t m1_servercertificatesprovisioning_api_metadata = { -M1_SERVERCERTIFICATESPROVISIONING_API_NAME, -M1_SERVERCERTIFICATESPROVISIONING_API_VERSION}; + M1_SERVERCERTIFICATESPROVISIONING_API_NAME, + M1_SERVERCERTIFICATESPROVISIONING_API_VERSION +}; const nf_server_interface_metadata_t m3_contenthostingprovisioning_api_metatdata = { -M3_CONTENTHOSTINGPROVISIONING_API_NAME, -M3_CONTENTHOSTINGPROVISIONING_API_VERSION}; + M3_CONTENTHOSTINGPROVISIONING_API_NAME, + M3_CONTENTHOSTINGPROVISIONING_API_VERSION +}; const nf_server_interface_metadata_t m5_serviceaccessinformation_api_metadata = { -M5_SERVICEACCESSINFORMATION_API_NAME, -M5_SERVICEACCESSINFORMATION_API_VERSION}; + M5_SERVICEACCESSINFORMATION_API_NAME, + M5_SERVICEACCESSINFORMATION_API_VERSION +}; void msaf_state_initial(ogs_fsm_t *s, msaf_event_t *e) { @@ -100,7 +107,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) switch (e->h.id) { case OGS_FSM_ENTRY_SIG: - ogs_info("[%s] MSAF Running", ogs_sbi_self()->nf_instance->id); + ogs_info("[%s] MSAF Running", ogs_sbi_self()->nf_instance->id); break; case OGS_FSM_EXIT_SIG: @@ -121,1025 +128,978 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); ogs_free(methods); - break; - } + break; + } rv = ogs_sbi_parse_header(&message, &request->h); if (rv != OGS_OK) { - ogs_error("ogs_sbi_parse_header() failed"); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "cannot parse HTTP message", NULL, NULL, NULL, app_meta)); - + ogs_error("ogs_sbi_parse_header() failed"); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "cannot parse HTTP message", NULL, NULL, NULL, app_meta)); + break; } SWITCH(message.h.service.name) - CASE(OGS_SBI_SERVICE_NAME_NNRF_NFM) - if (strcmp(message.h.api.version, OGS_SBI_API_V1) != 0) { - ogs_error("Not supported version [%s]", message.h.api.version); - ogs_assert(true == ogs_sbi_server_send_error( - stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, - &message, "Not supported version", NULL)); - ogs_sbi_message_free(&message); + CASE(OGS_SBI_SERVICE_NAME_NNRF_NFM) + if (strcmp(message.h.api.version, OGS_SBI_API_V1) != 0) { + ogs_error("Not supported version [%s]", message.h.api.version); + ogs_assert(true == ogs_sbi_server_send_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + &message, "Not supported version", NULL)); + ogs_sbi_message_free(&message); + break; + } + SWITCH(message.h.resource.component[0]) + CASE(OGS_SBI_RESOURCE_NAME_NF_STATUS_NOTIFY) + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) + ogs_nnrf_nfm_handle_nf_status_notify(stream, &message); break; - } - SWITCH(message.h.resource.component[0]) - CASE(OGS_SBI_RESOURCE_NAME_NF_STATUS_NOTIFY) - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_POST) - ogs_nnrf_nfm_handle_nf_status_notify(stream, &message); - break; - - DEFAULT - ogs_error("Invalid HTTP method [%s]", message.h.method); - ogs_assert(true == - ogs_sbi_server_send_error(stream, - OGS_SBI_HTTP_STATUS_FORBIDDEN, &message, - "Invalid HTTP method", message.h.method)); - END - break; - DEFAULT - ogs_error("Invalid resource name [%s]", - message.h.resource.component[0]); - ogs_assert(true == - ogs_sbi_server_send_error(stream, - OGS_SBI_HTTP_STATUS_BAD_REQUEST, &message, - "Invalid resource name", - message.h.resource.component[0])); + DEFAULT + ogs_error("Invalid HTTP method [%s]", message.h.method); + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_FORBIDDEN, &message, + "Invalid HTTP method", message.h.method)); END - ogs_sbi_message_free(&message); break; - CASE("3gpp-m1") - if (strcmp(message.h.api.version, "v2") != 0) { - char *error; - ogs_error("Not supported version [%s]", message.h.api.version); + DEFAULT + ogs_error("Invalid resource name [%s]", + message.h.resource.component[0]); + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_BAD_REQUEST, &message, + "Invalid resource name", + message.h.resource.component[0])); + END + ogs_sbi_message_free(&message); + break; - error = ogs_msprintf("Version [%s] not supported", message.h.api.version); + CASE("3gpp-m1") + if (strcmp(message.h.api.version, "v2") != 0) { + char *error; + ogs_error("Not supported version [%s]", message.h.api.version); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL, app_meta)); - - ogs_sbi_message_free(&message); - ogs_free(error); - break; - } - SWITCH(message.h.resource.component[0]) + error = ogs_msprintf("Version [%s] not supported", message.h.api.version); - CASE("provisioning-sessions") - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_POST) - - if (message.h.resource.component[1] && message.h.resource.component[2] && message.h.resource.component[3]) { - msaf_provisioning_session_t *msaf_provisioning_session; - - if (!strcmp(message.h.resource.component[2],"content-hosting-configuration") && !strcmp(message.h.resource.component[3],"purge")) { - { - ogs_hash_index_t *hi; - for (hi = ogs_hash_first(request->http.headers); - hi; hi = ogs_hash_next(hi)) { - if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { - if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/x-www-form-urlencoded")) { - char *err = NULL; - char *type = NULL; - type = (char *)ogs_hash_this_val(hi); - ogs_error("Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); - asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); - - ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - ogs_sbi_message_free(&message); - return; - - } - } - } - } - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if(msaf_provisioning_session) { - // process the POST body - purge_resource_id_node_t *purge_cache; - msaf_application_server_state_node_t *as_state; - assigned_provisioning_sessions_node_t *assigned_provisioning_sessions_resource; - const char *component = ogs_msprintf("%s/content-hosting-configuration/purge", message.h.resource.component[1]); - m1_purge_information_t *m1_purge_info = ogs_calloc(1, sizeof(m1_purge_information_t)); - m1_purge_info->m1_stream = stream; - m1_purge_info->m1_message = message; - - ogs_list_for_each(&msaf_provisioning_session->msaf_application_server_state_nodes, as_state) { - if(as_state->application_server && as_state->application_server->canonicalHostname) { - ogs_list_for_each(&as_state->assigned_provisioning_sessions,assigned_provisioning_sessions_resource){ - if(!strcmp(assigned_provisioning_sessions_resource->assigned_provisioning_session->provisioningSessionId, msaf_provisioning_session->provisioningSessionId)) { - - purge_cache = ogs_calloc(1, sizeof(purge_resource_id_node_t)); - ogs_assert(purge_cache); - purge_cache->provisioning_session_id = ogs_strdup(assigned_provisioning_sessions_resource->assigned_provisioning_session->provisioningSessionId); - - purge_cache->m1_purge_info = m1_purge_info; - m1_purge_info->refs++; - if(request->http.content) - purge_cache->purge_regex = ogs_strdup(request->http.content); - else - purge_cache->purge_regex = NULL; - - if (ogs_list_first(&as_state->purge_content_hosting_cache) == NULL) - ogs_list_init(&as_state->purge_content_hosting_cache); - - ogs_list_add(&as_state->purge_content_hosting_cache, purge_cache); - } else { - ogs_error("Provisioning Session [%s] is not assigned to an Application Server", message.h.resource.component[1]); - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] is not assigned to an Application Server", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session is not assigned to an Application Server.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - - } - } - } else { - ogs_error("Provisioning Session [%s]: Unable to get information about Application Server", message.h.resource.component[1]); - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] : Unable to get information about Application Server", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Unable to get information about Application Server", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - } - - next_action_for_application_server(as_state); - ogs_free(component); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL, app_meta)); - } - if (m1_purge_info->refs == 0) { - ogs_free(m1_purge_info); - // Send 204 back to M1 client - ogs_sbi_response_t *response; - response = nf_server_new_response(NULL, NULL, NULL, NULL, NULL, NULL, m1_contenthostingprovisioning_api, app_meta); - nf_server_populate_response(response, NULL, NULL, 204); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - } - } else { - ogs_error("Unable to retrieve the Provisioning Session [%s]", message.h.resource.component[1]); - char *err = NULL; - asprintf(&err,"Provisioning session [%s] does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - - } + ogs_sbi_message_free(&message); + ogs_free(error); + break; + } + SWITCH(message.h.resource.component[0]) - } - - } else if (message.h.resource.component[1] && message.h.resource.component[2]) { - msaf_provisioning_session_t *msaf_provisioning_session; - if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if(msaf_provisioning_session) { - // process the POST body - cJSON *entry; - int rv; - cJSON *chc; - cJSON *content_hosting_config = cJSON_Parse(request->http.content); - char *txt = cJSON_Print(content_hosting_config); - ogs_debug("txt:%s", txt); - - cJSON_ArrayForEach(entry, content_hosting_config) { - if(!strcmp(entry->string, "entryPointPath")){ - if(!uri_relative_check(entry->valuestring)) { - char *err = NULL; - asprintf(&err,"While creating the Content Hosting Configuration for the Provisioning Session [%s], entryPointPath does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring ); - ogs_error("While creating the Content Hosting Configuration for the Provisioning Session [%s], entryPointPath does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring); - - ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - - cJSON_Delete(content_hosting_config); - break; - } + CASE("provisioning-sessions") + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) - } - } + if (message.h.resource.component[1] && message.h.resource.component[2] && message.h.resource.component[3]) { + msaf_provisioning_session_t *msaf_provisioning_session; - if(msaf_provisioning_session->contentHostingConfiguration) { - OpenAPI_content_hosting_configuration_free(msaf_provisioning_session->contentHostingConfiguration); - msaf_provisioning_session->contentHostingConfiguration = NULL; + if (!strcmp(message.h.resource.component[2],"content-hosting-configuration") && !strcmp(message.h.resource.component[3],"purge")) { + ogs_hash_index_t *hi; + for (hi = ogs_hash_first(request->http.headers); + hi; hi = ogs_hash_next(hi)) { + if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { + if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/x-www-form-urlencoded")) { + char *err = NULL; + char *type = NULL; + type = (char *)ogs_hash_this_val(hi); + ogs_error("Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); + asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); - } + ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + ogs_sbi_message_free(&message); + return; - if (msaf_provisioning_session->serviceAccessInformation) { - OpenAPI_service_access_information_resource_free(msaf_provisioning_session->serviceAccessInformation); - msaf_provisioning_session->serviceAccessInformation = NULL; - } - - - rv = msaf_distribution_create(content_hosting_config, msaf_provisioning_session); - - if(rv){ - - ogs_debug("Content Hosting Configuration created successfully"); - msaf_application_server_state_set_on_post(msaf_provisioning_session); - chc = msaf_get_content_hosting_configuration_by_provisioning_session_id(message.h.resource.component[1]); - if (chc != NULL) { - char *text; - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, NULL, m1_contentprotocolsdiscovery_api, app_meta); - text = cJSON_Print(chc); - nf_server_populate_response(response, strlen(text), text, 201); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - cJSON_Delete(chc); - cJSON_Delete(content_hosting_config); - } else { - char *err = NULL; - ogs_error("Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); - asprintf(&err,"Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - - } - - + } + } + } + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if(msaf_provisioning_session) { + // process the POST body + purge_resource_id_node_t *purge_cache; + msaf_application_server_state_node_t *as_state; + assigned_provisioning_sessions_node_t *assigned_provisioning_sessions_resource; + m1_purge_information_t *m1_purge_info = ogs_calloc(1, sizeof(m1_purge_information_t)); + m1_purge_info->m1_stream = stream; + m1_purge_info->m1_message = message; + + ogs_list_for_each(&msaf_provisioning_session->msaf_application_server_state_nodes, as_state) { + if(as_state->application_server && as_state->application_server->canonicalHostname) { + ogs_list_for_each(&as_state->assigned_provisioning_sessions,assigned_provisioning_sessions_resource){ + if(!strcmp(assigned_provisioning_sessions_resource->assigned_provisioning_session->provisioningSessionId, msaf_provisioning_session->provisioningSessionId)) { + + purge_cache = ogs_calloc(1, sizeof(purge_resource_id_node_t)); + ogs_assert(purge_cache); + purge_cache->provisioning_session_id = ogs_strdup(assigned_provisioning_sessions_resource->assigned_provisioning_session->provisioningSessionId); + + purge_cache->m1_purge_info = m1_purge_info; + m1_purge_info->refs++; + if(request->http.content) + purge_cache->purge_regex = ogs_strdup(request->http.content); + else + purge_cache->purge_regex = NULL; + + if (ogs_list_first(&as_state->purge_content_hosting_cache) == NULL) + ogs_list_init(&as_state->purge_content_hosting_cache); + + ogs_list_add(&as_state->purge_content_hosting_cache, purge_cache); } else { + ogs_error("Provisioning Session [%s] is not assigned to an Application Server", message.h.resource.component[1]); char *err = NULL; - - ogs_error("Failed to populate Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); - asprintf(&err,"Creation of the Content Hosting Configuration failed for the Provisioning Session [%s]", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 500, 2, &message, "Creation of the Content Hosting Configuration failed.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - + asprintf(&err,"Provisioning Session [%s] is not assigned to an Application Server", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session is not assigned to an Application Server.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } - - } else { - char *err = NULL; - asprintf(&err,"Provisioning session [%s]does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - - } - + } else { + ogs_error("Provisioning Session [%s]: Unable to get information about Application Server", message.h.resource.component[1]); + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] : Unable to get information about Application Server", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Unable to get information about Application Server", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } - if (!strcmp(message.h.resource.component[2],"certificates")) { - ogs_info("POST certificates"); - ogs_hash_index_t *hi; - char *canonical_domain_name; - char *cert; - int csr = 0; - - { - for (hi = ogs_hash_first(request->http.params); - hi; hi = ogs_hash_next(hi)) { - if (!ogs_strcasecmp(ogs_hash_this_key(hi), "csr")) { - csr = 1; - break; - } - } - } - - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if (msaf_provisioning_session) { - if (csr) { - - msaf_certificate_t *csr_cert; - char *location; - int m1_server_certificates_response_max_age; - csr_cert = server_cert_new("newcsr", NULL); - ogs_sbi_response_t *response; - location = ogs_msprintf("%s/%s", request->h.uri, csr_cert->id); - if(csr_cert->cache_control_max_age){ - m1_server_certificates_response_max_age = csr_cert->cache_control_max_age; - } else { - m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; - } - response = nf_server_new_response(location, "application/x-pem-file", csr_cert->last_modified, csr_cert->server_certificate_hash, m1_server_certificates_response_max_age, NULL, m1_servercertificatesprovisioning_api, app_meta); - - nf_server_populate_response(response, strlen(csr_cert->certificate), ogs_strdup(csr_cert->certificate), 200); - - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - ogs_free(location); - if(csr_cert->server_certificate_hash) ogs_free(csr_cert->server_certificate_hash); - if(csr_cert->certificate) ogs_free(csr_cert->certificate); - ogs_free(csr_cert); - return; - } - if (ogs_list_first(&msaf_provisioning_session->msaf_application_servers) == NULL) { - msaf_application_server_node_t *msaf_as = NULL; - msaf_as = ogs_list_first(&msaf_self()->config.applicationServers_list); - canonical_domain_name = msaf_as->canonicalHostname; - ogs_list_init(&msaf_provisioning_session->msaf_application_server_state_nodes); - ogs_list_add(&msaf_provisioning_session->msaf_application_server_state_nodes, msaf_as); - } - ogs_info("canonical_domain_name): %s", canonical_domain_name); - cert = check_in_cert_list(canonical_domain_name); - if (cert != NULL) { - ogs_sbi_response_t *response; - char *location; - location = ogs_msprintf("%s/%s", request->h.uri, cert); - response = nf_server_new_response(location, NULL, 0, NULL, 0, NULL, m1_servercertificatesprovisioning_api, app_meta); - nf_server_populate_response(response, 0, NULL, 200); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - ogs_free(location); - } else { - msaf_certificate_t *new_cert; - int m1_server_certificates_response_max_age; - new_cert = server_cert_new("newcert", NULL); - ogs_sbi_response_t *response; - char *location; - location = ogs_msprintf("%s/%s", request->h.uri, new_cert->id); - if(new_cert->cache_control_max_age){ - m1_server_certificates_response_max_age = new_cert->cache_control_max_age; - } else { - m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; - } - response = nf_server_new_response(location, NULL, new_cert->last_modified, new_cert->server_certificate_hash, m1_server_certificates_response_max_age, NULL, m1_servercertificatesprovisioning_api, app_meta); - nf_server_populate_response(response, 0, NULL, 200); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - ogs_free(location); - if(new_cert->server_certificate_hash) ogs_free(new_cert->server_certificate_hash); - if (new_cert->certificate) ogs_free(new_cert->certificate); - ogs_free(new_cert); + next_action_for_application_server(as_state); + } + if (m1_purge_info->refs == 0) { + ogs_free(m1_purge_info); + // Send 204 back to M1 client + ogs_sbi_response_t *response; + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_contenthostingprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + } + } else { + ogs_error("Unable to retrieve the Provisioning Session [%s]", message.h.resource.component[1]); + char *err = NULL; + asprintf(&err,"Provisioning session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + } - } + } - } else { + } else if (message.h.resource.component[1] && message.h.resource.component[2]) { + msaf_provisioning_session_t *msaf_provisioning_session; + if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if(msaf_provisioning_session) { + // process the POST body + cJSON *entry; + int rv; + cJSON *chc; + cJSON *content_hosting_config = cJSON_Parse(request->http.content); + char *txt = cJSON_Print(content_hosting_config); + ogs_debug("body:%s", request->http.content); + ogs_debug("txt:%s", txt); + + cJSON_ArrayForEach(entry, content_hosting_config) { + if(!strcmp(entry->string, "entryPointPath")){ + if(!uri_relative_check(entry->valuestring)) { char *err = NULL; - asprintf(&err,"Provisioning session [%s] does not exists.", message.h.resource.component[1]); - ogs_error("Provisioning session [%s] does not exists.", message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - + asprintf(&err,"While creating the Content Hosting Configuration for the Provisioning Session [%s], entryPointPath does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring ); + ogs_error("While creating the Content Hosting Configuration for the Provisioning Session [%s], entryPointPath does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring); - } + ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + cJSON_Delete(content_hosting_config); + break; + } } + } - } else { - cJSON *entry; - cJSON *prov_sess = cJSON_Parse(request->http.content); - cJSON *provisioning_session; - char *provisioning_session_type, *external_app_id, *asp_id = NULL; - msaf_provisioning_session_t *msaf_provisioning_session; - - cJSON_ArrayForEach(entry, prov_sess) { - if(!strcmp(entry->string, "provisioningSessionType")){ - provisioning_session_type = entry->valuestring; - } - if(!strcmp(entry->string, "aspId")){ - asp_id = entry->valuestring; - } - if(!strcmp(entry->string, "externalApplicationId")){ - external_app_id = entry->valuestring; - } + if(msaf_provisioning_session->contentHostingConfiguration) { + OpenAPI_content_hosting_configuration_free(msaf_provisioning_session->contentHostingConfiguration); + msaf_provisioning_session->contentHostingConfiguration = NULL; - } - msaf_provisioning_session = msaf_provisioning_session_create(provisioning_session_type, asp_id, external_app_id); - provisioning_session = msaf_provisioning_session_get_json(msaf_provisioning_session->provisioningSessionId); - if (provisioning_session != NULL) { - ogs_sbi_response_t *response; + } + + if (msaf_provisioning_session->serviceAccessInformation) { + OpenAPI_service_access_information_resource_free(msaf_provisioning_session->serviceAccessInformation); + msaf_provisioning_session->serviceAccessInformation = NULL; + } + + rv = msaf_distribution_create(content_hosting_config, msaf_provisioning_session); + + if(rv){ + + ogs_debug("Content Hosting Configuration created successfully"); + msaf_application_server_state_set_on_post(msaf_provisioning_session); + chc = msaf_get_content_hosting_configuration_by_provisioning_session_id(message.h.resource.component[1]); + if (chc != NULL) { char *text; - char *location; - text = cJSON_Print(provisioning_session); - if (request->h.uri[strlen(request->h.uri)-1] != '/') { - location = ogs_msprintf("%s/%s", request->h.uri,msaf_provisioning_session->provisioningSessionId); - } else { - location = ogs_msprintf("%s%s", request->h.uri,msaf_provisioning_session->provisioningSessionId); - } - response = nf_server_new_response(location, "application/json", msaf_provisioning_session->provisioningSessionReceived, msaf_provisioning_session->provisioningSessionHash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, m1_provisioningsession_api, app_meta); - + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, NULL, m1_contentprotocolsdiscovery_api, app_meta); + text = cJSON_Print(chc); nf_server_populate_response(response, strlen(text), text, 201); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - ogs_free(location); - cJSON_Delete(provisioning_session); - cJSON_Delete(prov_sess); + cJSON_Delete(chc); + cJSON_Delete(content_hosting_config); } else { char *err = NULL; - asprintf(&err,"Creation of the Provisioning session failed."); - ogs_error("Creation of the Provisioning session failed."); - ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); - + ogs_error("Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); + asprintf(&err,"Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } + } else { + char *err = NULL; + + ogs_error("Failed to populate Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); + asprintf(&err,"Creation of the Content Hosting Configuration failed for the Provisioning Session [%s]", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 500, 2, &message, "Creation of the Content Hosting Configuration failed.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } - break; + } else { + char *err = NULL; + asprintf(&err,"Provisioning session [%s]does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); - CASE(OGS_SBI_HTTP_METHOD_GET) - if (message.h.resource.component[1] && message.h.resource.component[2] && message.h.resource.component[3]) { - if (!strcmp(message.h.resource.component[2],"certificates") ) { - msaf_provisioning_session_t *msaf_provisioning_session; - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if (msaf_provisioning_session) { - msaf_certificate_t *cert; - ogs_sbi_response_t *response; + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - cert = server_cert_retrieve(message.h.resource.component[3]); - if(!cert) { - ogs_error("unable to retrieve certificate [%s]", message.h.resource.component[3]); - char *err = NULL; - asprintf(&err,"Unable to retrieve Certificate not yet available"); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate not yet available.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - return; - } - - if(!cert->return_code) { - int m1_server_certificates_response_max_age; - if(cert->cache_control_max_age){ - m1_server_certificates_response_max_age = cert->cache_control_max_age; - } else { - m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; - } - response = nf_server_new_response(NULL, "application/x-pem-file", cert->last_modified, cert->server_certificate_hash, m1_server_certificates_response_max_age, NULL, m1_servercertificatesprovisioning_api, app_meta); - nf_server_populate_response(response, strlen(cert->certificate), ogs_strdup(cert->certificate), 200); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - } else if(cert->return_code == 4){ - char *err = NULL; - asprintf(&err,"Certificate [%s] does not exists.", cert->id); - ogs_error("Certificate [%s] does not exists.", cert->id); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - - } else if(cert->return_code == 8){ - char *err = NULL; - asprintf(&err,"Certificate [%s] not yet available.", cert->id); - ogs_error("Certificate [%s] not yet available.", cert->id); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate not yet available.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + } - + } + if (!strcmp(message.h.resource.component[2],"certificates")) { + ogs_info("POST certificates"); + ogs_hash_index_t *hi; + char *canonical_domain_name; + char *cert; + int csr = 0; + + for (hi = ogs_hash_first(request->http.params); + hi; hi = ogs_hash_next(hi)) { + if (!ogs_strcasecmp(ogs_hash_this_key(hi), "csr")) { + csr = 1; + break; + } + } + + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if (msaf_provisioning_session) { + msaf_application_server_node_t *msaf_as = NULL; + msaf_as = ogs_list_first(&msaf_self()->config.applicationServers_list); + canonical_domain_name = msaf_as->canonicalHostname; + ogs_info("canonical_domain_name: %s", canonical_domain_name); + + if (csr) { + msaf_certificate_t *csr_cert; + char *location; + int m1_server_certificates_response_max_age; + csr_cert = server_cert_new("newcsr", canonical_domain_name); + ogs_sbi_response_t *response; + location = ogs_msprintf("%s/%s", request->h.uri, csr_cert->id); + if(csr_cert->cache_control_max_age){ + m1_server_certificates_response_max_age = csr_cert->cache_control_max_age; + } else { + m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; + } + response = nf_server_new_response(location, "application/x-pem-file", csr_cert->last_modified, csr_cert->server_certificate_hash, m1_server_certificates_response_max_age, NULL, m1_servercertificatesprovisioning_api, app_meta); - } else { - char *err = NULL; - asprintf(&err,"Certificate [%s] management problem.", cert->id); - ogs_error("Certificate [%s] management problem.", cert->id); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + nf_server_populate_response(response, strlen(csr_cert->certificate), ogs_strdup(csr_cert->certificate), 200); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + ogs_free(location); + msaf_certificate_free(csr_cert); - } - ogs_free(cert->certificate); - ogs_free(cert); + return; + } - } else { - char *err = NULL; - asprintf(&err,"Provisioning session [%s] is not available.", message.h.resource.component[1]); - ogs_error("Provisioning session [%s] is not available.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - + if (ogs_list_first(&msaf_provisioning_session->msaf_application_servers) == NULL) { + ogs_list_init(&msaf_provisioning_session->msaf_application_server_state_nodes); + ogs_list_add(&msaf_provisioning_session->msaf_application_server_state_nodes, msaf_as); + } - } + cert = check_in_cert_list(canonical_domain_name); + if (cert != NULL) { + ogs_sbi_response_t *response; + char *location; + location = ogs_msprintf("%s/%s", request->h.uri, cert); + response = nf_server_new_response(location, NULL, 0, NULL, 0, NULL, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 200); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + ogs_free(location); + } else { + msaf_certificate_t *new_cert; + int m1_server_certificates_response_max_age; + new_cert = server_cert_new("newcert", canonical_domain_name); + ogs_sbi_response_t *response; + char *location; + location = ogs_msprintf("%s/%s", request->h.uri, new_cert->id); + if(new_cert->cache_control_max_age){ + m1_server_certificates_response_max_age = new_cert->cache_control_max_age; + } else { + m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; } + response = nf_server_new_response(location, NULL, new_cert->last_modified, new_cert->server_certificate_hash, m1_server_certificates_response_max_age, NULL, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 200); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + ogs_free(location); + msaf_certificate_free(new_cert); } - else - if (message.h.resource.component[1] && message.h.resource.component[2]) { - msaf_provisioning_session_t *msaf_provisioning_session; - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { - if(msaf_provisioning_session) { - cJSON *chc; - chc = msaf_get_content_hosting_configuration_by_provisioning_session_id(message.h.resource.component[1]); - if (chc != NULL) { - ogs_sbi_response_t *response; - char *text; - text = cJSON_Print(chc); - - response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, NULL, m1_contenthostingprovisioning_api, app_meta); - ogs_assert(response); - nf_server_populate_response(response, strlen(text), text, 200); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - - cJSON_Delete(chc); - } else { - char *err = NULL; - ogs_error("Provisioning Session [%s]: Unable to retrieve the Content Hosting Configuration", message.h.resource.component[1]); - asprintf(&err,"Provisioning Session [%s]: Unable to retrieve the Content Hosting Configuration", message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - - - - } + } else { + char *err = NULL; + asprintf(&err,"Provisioning session [%s] does not exists.", message.h.resource.component[1]); + ogs_error("Provisioning session [%s] does not exists.", message.h.resource.component[1]); - } else { - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + } + } + } else { + cJSON *entry; + cJSON *prov_sess = cJSON_Parse(request->http.content); + cJSON *provisioning_session; + char *provisioning_session_type, *external_app_id, *asp_id = NULL; + msaf_provisioning_session_t *msaf_provisioning_session; + + cJSON_ArrayForEach(entry, prov_sess) { + if(!strcmp(entry->string, "provisioningSessionType")){ + provisioning_session_type = entry->valuestring; + } + if(!strcmp(entry->string, "aspId")){ + asp_id = entry->valuestring; + } + if(!strcmp(entry->string, "externalApplicationId")){ + external_app_id = entry->valuestring; + } + } + msaf_provisioning_session = msaf_provisioning_session_create(provisioning_session_type, asp_id, external_app_id); + provisioning_session = msaf_provisioning_session_get_json(msaf_provisioning_session->provisioningSessionId); + if (provisioning_session != NULL) { + ogs_sbi_response_t *response; + char *text; + char *location; + text = cJSON_Print(provisioning_session); + if (request->h.uri[strlen(request->h.uri)-1] != '/') { + location = ogs_msprintf("%s/%s", request->h.uri,msaf_provisioning_session->provisioningSessionId); + } else { + location = ogs_msprintf("%s%s", request->h.uri,msaf_provisioning_session->provisioningSessionId); + } + response = nf_server_new_response(location, "application/json", msaf_provisioning_session->provisioningSessionReceived, msaf_provisioning_session->provisioningSessionHash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, m1_provisioningsession_api, app_meta); + + nf_server_populate_response(response, strlen(text), text, 201); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + ogs_free(location); + cJSON_Delete(provisioning_session); + cJSON_Delete(prov_sess); + } else { + char *err = NULL; + asprintf(&err,"Creation of the Provisioning session failed."); + ogs_error("Creation of the Provisioning session failed."); + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); + } + } - } + break; - } else if (!strcmp(message.h.resource.component[2],"protocols")) { - if(msaf_provisioning_session) { - ogs_sbi_response_t *response; - ogs_info("CONTENT_PROTOCOLS_DISCOVERY_JSON: %s", CONTENT_PROTOCOLS_DISCOVERY_JSON); - response = nf_server_new_response(NULL, "application/json", CONTENT_PROTOCOLS_DISCOVERY_JSON_TIME, CONTENT_PROTOCOLS_DISCOVERY_JSON_HASH, msaf_self()->config.server_response_cache_control->m1_content_protocols_response_max_age, NULL, m1_contentprotocolsdiscovery_api, app_meta); - ogs_assert(response); - nf_server_populate_response(response, strlen(CONTENT_PROTOCOLS_DISCOVERY_JSON), ogs_strdup(CONTENT_PROTOCOLS_DISCOVERY_JSON), 200); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - } else { - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contentprotocolsdiscovery_api, app_meta)); - } - } - } else if (message.h.resource.component[1]) { - msaf_provisioning_session_t *msaf_provisioning_session = NULL; - cJSON *provisioning_session = NULL; + CASE(OGS_SBI_HTTP_METHOD_GET) + if (message.h.resource.component[1] && message.h.resource.component[2] && message.h.resource.component[3]) { + if (!strcmp(message.h.resource.component[2],"certificates") ) { + msaf_provisioning_session_t *msaf_provisioning_session; + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if (msaf_provisioning_session) { + msaf_certificate_t *cert; + ogs_sbi_response_t *response; + + cert = server_cert_retrieve(message.h.resource.component[3]); + + if(!cert) { + ogs_error("unable to retrieve certificate [%s]", message.h.resource.component[3]); + char *err = NULL; + asprintf(&err,"Unable to retrieve Certificate not yet available"); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate not yet available.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + return; + } - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if(!cert->return_code) { + int m1_server_certificates_response_max_age; + if(cert->cache_control_max_age){ + m1_server_certificates_response_max_age = cert->cache_control_max_age; + } else { + m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; + } + response = nf_server_new_response(NULL, "application/x-pem-file", cert->last_modified, cert->server_certificate_hash, m1_server_certificates_response_max_age, NULL, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, strlen(cert->certificate), ogs_strdup(cert->certificate), 200); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + } else if(cert->return_code == 4){ + char *err = NULL; + asprintf(&err,"Certificate [%s] does not exists.", cert->id); + ogs_error("Certificate [%s] does not exists.", cert->id); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + + } else if(cert->return_code == 8){ + char *err = NULL; + asprintf(&err,"Certificate [%s] not yet available.", cert->id); + ogs_error("Certificate [%s] not yet available.", cert->id); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate not yet available.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + } else { + char *err = NULL; + asprintf(&err,"Certificate [%s] management problem.", cert->id); + ogs_error("Certificate [%s] management problem.", cert->id); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + } + msaf_certificate_free(cert); + + } else { + char *err = NULL; + asprintf(&err,"Provisioning session [%s] is not available.", message.h.resource.component[1]); + ogs_error("Provisioning session [%s] is not available.", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + } + } + } else if (message.h.resource.component[1] && message.h.resource.component[2]) { + msaf_provisioning_session_t *msaf_provisioning_session; + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { + if(msaf_provisioning_session) { + cJSON *chc; + chc = msaf_get_content_hosting_configuration_by_provisioning_session_id(message.h.resource.component[1]); + if (chc != NULL) { + ogs_sbi_response_t *response; + char *text; + text = cJSON_Print(chc); - provisioning_session = msaf_provisioning_session_get_json(message.h.resource.component[1]); + response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, NULL, m1_contenthostingprovisioning_api, app_meta); + ogs_assert(response); + nf_server_populate_response(response, strlen(text), text, 200); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - if (provisioning_session && msaf_provisioning_session && !msaf_provisioning_session->marked_for_deletion) { - ogs_sbi_response_t *response; - char *text; - text = cJSON_Print(provisioning_session); - - response = nf_server_new_response(NULL, "application/json", msaf_provisioning_session->provisioningSessionReceived, msaf_provisioning_session->provisioningSessionHash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, m1_provisioningsession_api, app_meta); - - nf_server_populate_response(response, strlen(text), text, 200); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - cJSON_Delete(provisioning_session); + cJSON_Delete(chc); + } else { + char *err = NULL; + ogs_error("Provisioning Session [%s]: Unable to retrieve the Content Hosting Configuration", message.h.resource.component[1]); + asprintf(&err,"Provisioning Session [%s]: Unable to retrieve the Content Hosting Configuration", message.h.resource.component[1]); - } else { - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] is not available.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] is not available.", message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL, m1_provisioningsession_api, app_meta)); - } + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } - break; - - CASE(OGS_SBI_HTTP_METHOD_PUT) - if (message.h.resource.component[1] && message.h.resource.component[2]) { - - ogs_info("PUT: %s", message.h.resource.component[1]); - msaf_provisioning_session_t *msaf_provisioning_session; - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if(msaf_provisioning_session) { - ogs_info("PUT: with msaf_provisioning_session: %s", message.h.resource.component[1]); - if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { - - // process the POST body - cJSON *entry; - int rv; - cJSON *content_hosting_config = cJSON_Parse(request->http.content); - char *txt = cJSON_Print(content_hosting_config); - ogs_debug("txt:%s", txt); - - cJSON_ArrayForEach(entry, content_hosting_config) { - if(!strcmp(entry->string, "entryPointPath")){ - if(!uri_relative_check(entry->valuestring)) { - char *err = NULL; - asprintf(&err,"While updating the Content Hosting Configuration for the Provisioning Session [%s], Entry Point Path does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring ); - ogs_error("While updating the Content Hosting Configuration for the provisioning Session [%s], Entry Point Path does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring); - - ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - - cJSON_Delete(content_hosting_config); - break; - } - } - } - if(msaf_provisioning_session->contentHostingConfiguration) { - OpenAPI_content_hosting_configuration_free(msaf_provisioning_session->contentHostingConfiguration); - msaf_provisioning_session->contentHostingConfiguration = NULL; + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + + } + + } else if (!strcmp(message.h.resource.component[2],"protocols")) { + if(msaf_provisioning_session) { + ogs_sbi_response_t *response; + ogs_info("CONTENT_PROTOCOLS_DISCOVERY_JSON: %s", CONTENT_PROTOCOLS_DISCOVERY_JSON); + response = nf_server_new_response(NULL, "application/json", CONTENT_PROTOCOLS_DISCOVERY_JSON_TIME, CONTENT_PROTOCOLS_DISCOVERY_JSON_HASH, msaf_self()->config.server_response_cache_control->m1_content_protocols_response_max_age, NULL, m1_contentprotocolsdiscovery_api, app_meta); + ogs_assert(response); + nf_server_populate_response(response, strlen(CONTENT_PROTOCOLS_DISCOVERY_JSON), ogs_strdup(CONTENT_PROTOCOLS_DISCOVERY_JSON), 200); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contentprotocolsdiscovery_api, app_meta)); + } + } + } else if (message.h.resource.component[1]) { + msaf_provisioning_session_t *msaf_provisioning_session = NULL; + cJSON *provisioning_session = NULL; - } + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if (msaf_provisioning_session->serviceAccessInformation) { - OpenAPI_service_access_information_resource_free(msaf_provisioning_session->serviceAccessInformation); - msaf_provisioning_session->serviceAccessInformation = NULL; - } + provisioning_session = msaf_provisioning_session_get_json(message.h.resource.component[1]); + if (provisioning_session && msaf_provisioning_session && !msaf_provisioning_session->marked_for_deletion) { + ogs_sbi_response_t *response; + char *text; + text = cJSON_Print(provisioning_session); - rv = msaf_distribution_create(content_hosting_config, msaf_provisioning_session); + response = nf_server_new_response(NULL, "application/json", msaf_provisioning_session->provisioningSessionReceived, msaf_provisioning_session->provisioningSessionHash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, m1_provisioningsession_api, app_meta); - if(rv){ + nf_server_populate_response(response, strlen(text), text, 200); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + cJSON_Delete(provisioning_session); - msaf_application_server_state_update(msaf_provisioning_session); + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] is not available.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] is not available.", message.h.resource.component[1]); - ogs_debug("Content Hosting Configuration updated successfully"); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL, m1_provisioningsession_api, app_meta)); + } + } + break; - ogs_sbi_response_t *response; - response = ogs_sbi_response_new(); - response->status = 204; - ogs_sbi_header_set(response->http.headers, "Content-Type", "application/json"); - ogs_sbi_header_set(response->http.headers, "Location", request->h.uri); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - cJSON_Delete(content_hosting_config); + CASE(OGS_SBI_HTTP_METHOD_PUT) + if (message.h.resource.component[1] && message.h.resource.component[2]) { + + ogs_info("PUT: %s", message.h.resource.component[1]); + msaf_provisioning_session_t *msaf_provisioning_session; + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if(msaf_provisioning_session) { + ogs_info("PUT: with msaf_provisioning_session: %s", message.h.resource.component[1]); + if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { + + // process the POST body + cJSON *entry; + int rv; + cJSON *content_hosting_config = cJSON_Parse(request->http.content); + char *txt = cJSON_Print(content_hosting_config); + ogs_debug("txt:%s", txt); + + cJSON_ArrayForEach(entry, content_hosting_config) { + if(!strcmp(entry->string, "entryPointPath")){ + if(!uri_relative_check(entry->valuestring)) { + char *err = NULL; + asprintf(&err,"While updating the Content Hosting Configuration for the Provisioning Session [%s], Entry Point Path does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring ); + ogs_error("While updating the Content Hosting Configuration for the provisioning Session [%s], Entry Point Path does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring); - } else { - char *err = NULL; - ogs_error("Provisioning Session [%s]: Failed to update the Content Hosting Configuration.", message.h.resource.component[1]); - asprintf(&err,"Provisioning Session [%s]: Update to Content Hosting Configuration failed.", message.h.resource.component[1]); - ogs_error("Update of the Content Hosting Configuration failed."); - - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Failed to update the contentHostingConfiguration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - } + cJSON_Delete(content_hosting_config); + break; } - if (message.h.resource.component[1] && !strcmp(message.h.resource.component[2],"certificates") && message.h.resource.component[3]) { - char *cert_id; - char *cert; - int rv; - ogs_sbi_response_t *response; - msaf_provisioning_session_t *msaf_provisioning_session; - - { - ogs_hash_index_t *hi; - for (hi = ogs_hash_first(request->http.headers); - hi; hi = ogs_hash_next(hi)) { - if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { - if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/x-pem-file")) { - char *err = NULL; - char *type = NULL; - type = (char *)ogs_hash_this_val(hi); - ogs_error("Unsupported Media Type: received type: %s, should have been application/x-pem-file", type); - asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-pem-file", type); - - ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - ogs_sbi_message_free(&message); - return; - - } - } - } - } + } + } + if(msaf_provisioning_session->contentHostingConfiguration) { + OpenAPI_content_hosting_configuration_free(msaf_provisioning_session->contentHostingConfiguration); + msaf_provisioning_session->contentHostingConfiguration = NULL; + } - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if (msaf_provisioning_session->serviceAccessInformation) { + OpenAPI_service_access_information_resource_free(msaf_provisioning_session->serviceAccessInformation); + msaf_provisioning_session->serviceAccessInformation = NULL; + } - if(msaf_provisioning_session) { - cert_id = message.h.resource.component[3]; - cert = ogs_strdup(request->http.content); - rv = server_cert_set(cert_id, cert); - // response = ogs_sbi_response_new(); + rv = msaf_distribution_create(content_hosting_config, msaf_provisioning_session); + if(rv){ - if (rv == 0){ - response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_servercertificatesprovisioning_api, app_meta); - nf_server_populate_response(response, 0, NULL, 204); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - } else if (rv == 3 ) { + msaf_application_server_state_update(msaf_provisioning_session); - char *err = NULL; - ogs_error("A server certificate with id [%s] already exist", cert_id); - asprintf(&err,"A server certificate with id [%s] already exist", cert_id); - ogs_assert(true == nf_server_send_error(stream, 403, 3, &message, "A server certificate already exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - - } else if(rv == 4) { - char *err = NULL; - ogs_error("Server certificate with id [%s] does not exist", cert_id); - asprintf(&err,"Server certificate with id [%s] does not exist", cert_id); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Server certificate does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - - } else if(rv == 5) { - char *err = NULL; - ogs_error("CSR was never generated for this certificate Id [%s]", cert_id); - asprintf(&err,"CSR was never generated for this certificate Id [%s]", cert_id); - ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "CSR was never generated for the certificate.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + ogs_debug("Content Hosting Configuration updated successfully"); + ogs_sbi_response_t *response; + response = ogs_sbi_response_new(); + response->status = 204; + ogs_sbi_header_set(response->http.headers, "Content-Type", "application/json"); + ogs_sbi_header_set(response->http.headers, "Location", request->h.uri); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + cJSON_Delete(content_hosting_config); - } else if(rv == 6) { - char *err = NULL; - ogs_error("The public certificate [%s] provided does not match the key", cert_id); - asprintf(&err,"The public certificate [%s] provided does not match the key", cert_id); - ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "The public certificate provided does not match the key.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - - } else { - char *err = NULL; - ogs_error("There was a certificate management problem for the certificate id [%s]", cert_id); - asprintf(&err,"There was a certificate management problem for the certificate id [%s].", cert_id); - - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "There was a certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - + } else { + char *err = NULL; + ogs_error("Provisioning Session [%s]: Failed to update the Content Hosting Configuration.", message.h.resource.component[1]); + asprintf(&err,"Provisioning Session [%s]: Update to Content Hosting Configuration failed.", message.h.resource.component[1]); + ogs_error("Update of the Content Hosting Configuration failed."); - } - ogs_free(cert); - } + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Failed to update the contentHostingConfiguration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - } + } + } + if (message.h.resource.component[1] && !strcmp(message.h.resource.component[2],"certificates") && message.h.resource.component[3]) { + char *cert_id; + char *cert; + int rv; + ogs_sbi_response_t *response; + msaf_provisioning_session_t *msaf_provisioning_session; + + { + ogs_hash_index_t *hi; + for (hi = ogs_hash_first(request->http.headers); + hi; hi = ogs_hash_next(hi)) { + if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { + if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/x-pem-file")) { + char *err = NULL; + char *type = NULL; + type = (char *)ogs_hash_this_val(hi); + ogs_error("Unsupported Media Type: received type: %s, should have been application/x-pem-file", type); + asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-pem-file", type); - } else { - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + ogs_sbi_message_free(&message); + return; + } + } } - - } - break; - - CASE(OGS_SBI_HTTP_METHOD_DELETE) - - if (message.h.resource.component[1] && !strcmp(message.h.resource.component[2],"certificates") && message.h.resource.component[3]) { - ogs_sbi_response_t *response; - msaf_provisioning_session_t *provisioning_session = NULL; - provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if (provisioning_session) { - int rv; - rv = server_cert_delete(message.h.resource.component[3]); - if ((rv == 0) || (rv == 8)){ - response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_servercertificatesprovisioning_api, app_meta); - nf_server_populate_response(response, 0, NULL, 204); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - } else if (rv == 4 ) { - char *err = NULL; - asprintf(&err,"Certificate [%s] does not exist.", message.h.resource.component[3]); - ogs_error("Certificate [%s] does not exist.", message.h.resource.component[3]); - - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - } else { + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + + if(msaf_provisioning_session) { + cert_id = message.h.resource.component[3]; + cert = ogs_strdup(request->http.content); + rv = server_cert_set(cert_id, cert); + // response = ogs_sbi_response_new(); + + if (rv == 0){ + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + } else if (rv == 3 ) { + char *err = NULL; - asprintf(&err,"Certificate management problem for certificate [%s].", message.h.resource.component[3]); - ogs_error("Certificate management problem."); - - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - + ogs_error("A server certificate with id [%s] already exist", cert_id); + asprintf(&err,"A server certificate with id [%s] already exist", cert_id); + ogs_assert(true == nf_server_send_error(stream, 403, 3, &message, "A server certificate already exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - } + } else if(rv == 4) { + char *err = NULL; + ogs_error("Server certificate with id [%s] does not exist", cert_id); + asprintf(&err,"Server certificate with id [%s] does not exist", cert_id); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Server certificate does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + } else if(rv == 5) { + char *err = NULL; + ogs_error("CSR was never generated for this certificate Id [%s]", cert_id); + asprintf(&err,"CSR was never generated for this certificate Id [%s]", cert_id); + ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "CSR was never generated for the certificate.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + } else if(rv == 6) { + char *err = NULL; + ogs_error("The public certificate [%s] provided does not match the key", cert_id); + asprintf(&err,"The public certificate [%s] provided does not match the key", cert_id); + ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "The public certificate provided does not match the key.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } else { char *err = NULL; - asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - + ogs_error("There was a certificate management problem for the certificate id [%s]", cert_id); + asprintf(&err,"There was a certificate management problem for the certificate id [%s].", cert_id); + + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "There was a certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - } - } else if (message.h.resource.component[1] && message.h.resource.component[2]) { - msaf_provisioning_session_t *msaf_provisioning_session; - ogs_sbi_response_t *response; - if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if(msaf_provisioning_session){ - if(msaf_provisioning_session && msaf_provisioning_session->contentHostingConfiguration) { - msaf_delete_content_hosting_configuration(message.h.resource.component[1]); - OpenAPI_content_hosting_configuration_free(msaf_provisioning_session->contentHostingConfiguration); - msaf_provisioning_session->contentHostingConfiguration = NULL; - response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_contenthostingprovisioning_api, app_meta); - ogs_assert(response); - nf_server_populate_response(response, 0, NULL, 204); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - break; - } else { - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] has no Content Hosting Configuration.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] has no Content Hosting Configuration.", message.h.resource.component[1] ); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Content Hosting Configuration does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - } - } else { - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] does not exists.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] does not exists.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - } } + ogs_free(cert); + } - } else if (message.h.resource.component[1]) { - ogs_sbi_response_t *response; - msaf_provisioning_session_t *provisioning_session = NULL; - provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if(!provisioning_session || provisioning_session->marked_for_deletion){ - char *err = NULL; - asprintf(&err,"Provisioning session [%s] either not found or already marked for deletion.", message.h.resource.component[1]); + } - ogs_error("Provisioning session [%s] either not found or already marked for deletion.",message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session either not found or already marked for deletion.", err, NULL, m1_provisioningsession_api, app_meta)); - - } else { - provisioning_session->marked_for_deletion = 1; - response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_provisioningsession_api, app_meta); - ogs_assert(response); - nf_server_populate_response(response, 0, NULL, 202); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - msaf_delete_content_hosting_configuration(message.h.resource.component[1]); - msaf_delete_certificate(message.h.resource.component[1]); - msaf_context_provisioning_session_free(provisioning_session); - msaf_provisioning_session_hash_remove(message.h.resource.component[1]); - } + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + + } + + + } + break; + + CASE(OGS_SBI_HTTP_METHOD_DELETE) + + if (message.h.resource.component[1] && !strcmp(message.h.resource.component[2],"certificates") && message.h.resource.component[3]) { + ogs_sbi_response_t *response; + msaf_provisioning_session_t *provisioning_session = NULL; + provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if (provisioning_session) { + int rv; + rv = server_cert_delete(message.h.resource.component[3]); + if ((rv == 0) || (rv == 8)){ + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + } else if (rv == 4 ) { + char *err = NULL; + asprintf(&err,"Certificate [%s] does not exist.", message.h.resource.component[3]); + ogs_error("Certificate [%s] does not exist.", message.h.resource.component[3]); + + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + + } else { + char *err = NULL; + asprintf(&err,"Certificate management problem for certificate [%s].", message.h.resource.component[3]); + ogs_error("Certificate management problem."); + + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + } + + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + + + } + } else if (message.h.resource.component[1] && message.h.resource.component[2]) { + msaf_provisioning_session_t *msaf_provisioning_session; + ogs_sbi_response_t *response; + if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if(msaf_provisioning_session){ + if(msaf_provisioning_session && msaf_provisioning_session->contentHostingConfiguration) { + msaf_delete_content_hosting_configuration(message.h.resource.component[1]); + OpenAPI_content_hosting_configuration_free(msaf_provisioning_session->contentHostingConfiguration); + msaf_provisioning_session->contentHostingConfiguration = NULL; + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_contenthostingprovisioning_api, app_meta); + ogs_assert(response); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + break; + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] has no Content Hosting Configuration.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] has no Content Hosting Configuration.", message.h.resource.component[1] ); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Content Hosting Configuration does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] does not exists.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] does not exists.", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + } - break; - CASE(OGS_SBI_HTTP_METHOD_OPTIONS) - - if (!strcmp(message.h.resource.component[0],"provisioning-sessions")){ - ogs_sbi_response_t *response; - char *methods = NULL; - - if (message.h.resource.component[1]) { - msaf_provisioning_session_t *provisioning_session = NULL; - provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if (provisioning_session) { - if (message.h.resource.component[2]) { - - - if (!strcmp(message.h.resource.component[2],"certificates")) { - if (message.h.resource.component[3]) { - msaf_certificate_t *cert; - cert = server_cert_retrieve(message.h.resource.component[3]); - if(cert){ - methods = ogs_msprintf("%s, %s, %s, %s",OGS_SBI_HTTP_METHOD_GET, OGS_SBI_HTTP_METHOD_PUT, OGS_SBI_HTTP_METHOD_DELETE, OGS_SBI_HTTP_METHOD_OPTIONS); - response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_servercertificatesprovisioning_api, app_meta); - nf_server_populate_response(response, 0, NULL, 204); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - ogs_free(cert->certificate); - ogs_free(cert); - } else { - char *err = NULL; - ogs_error("Method [%s]: Unable to retrieve certificate [%s]", message.h.method, message.h.resource.component[3]); - asprintf(&err,"Method [%s]: Unable to retrieve certificate [%s]", message.h.method, message.h.resource.component[3]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Unable to retrieve certificate.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - - } - } else { - methods = ogs_msprintf("%s",OGS_SBI_HTTP_METHOD_POST); - response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_servercertificatesprovisioning_api, app_meta); - nf_server_populate_response(response, 0, NULL, 204); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - } - - } else if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { - methods = ogs_msprintf("%s, %s, %s, %s, %s",OGS_SBI_HTTP_METHOD_POST, OGS_SBI_HTTP_METHOD_GET, OGS_SBI_HTTP_METHOD_PUT, OGS_SBI_HTTP_METHOD_DELETE, OGS_SBI_HTTP_METHOD_OPTIONS); - response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_contenthostingprovisioning_api, app_meta); - nf_server_populate_response(response, 0, NULL, 204); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - - } else { - char *err = NULL; - asprintf(&err,"Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[2]); - ogs_error("Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[2]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Target not yet supported.", err, NULL, NULL, app_meta)); - } - } else { - methods = ogs_msprintf("%s, %s, %s", OGS_SBI_HTTP_METHOD_GET, OGS_SBI_HTTP_METHOD_DELETE, OGS_SBI_HTTP_METHOD_OPTIONS); - response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_provisioningsession_api, app_meta); + } + + } else if (message.h.resource.component[1]) { + ogs_sbi_response_t *response; + msaf_provisioning_session_t *provisioning_session = NULL; + provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if(!provisioning_session || provisioning_session->marked_for_deletion){ + char *err = NULL; + asprintf(&err,"Provisioning session [%s] either not found or already marked for deletion.", message.h.resource.component[1]); + + ogs_error("Provisioning session [%s] either not found or already marked for deletion.",message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session either not found or already marked for deletion.", err, NULL, m1_provisioningsession_api, app_meta)); + + } else { + provisioning_session->marked_for_deletion = 1; + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_provisioningsession_api, app_meta); + ogs_assert(response); + nf_server_populate_response(response, 0, NULL, 202); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + msaf_delete_content_hosting_configuration(message.h.resource.component[1]); + msaf_delete_certificate(message.h.resource.component[1]); + msaf_context_provisioning_session_free(provisioning_session); + msaf_provisioning_session_hash_remove(message.h.resource.component[1]); + } + } + + break; + CASE(OGS_SBI_HTTP_METHOD_OPTIONS) + + if (!strcmp(message.h.resource.component[0],"provisioning-sessions")){ + ogs_sbi_response_t *response; + char *methods = NULL; + + if (message.h.resource.component[1]) { + msaf_provisioning_session_t *provisioning_session = NULL; + provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if (provisioning_session) { + if (message.h.resource.component[2]) { + + + if (!strcmp(message.h.resource.component[2],"certificates")) { + if (message.h.resource.component[3]) { + msaf_certificate_t *cert; + cert = server_cert_retrieve(message.h.resource.component[3]); + if(cert){ + methods = ogs_msprintf("%s, %s, %s, %s",OGS_SBI_HTTP_METHOD_GET, OGS_SBI_HTTP_METHOD_PUT, OGS_SBI_HTTP_METHOD_DELETE, OGS_SBI_HTTP_METHOD_OPTIONS); + response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_servercertificatesprovisioning_api, app_meta); nf_server_populate_response(response, 0, NULL, 204); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - + msaf_certificate_free(cert); + } else { + char *err = NULL; + ogs_error("Method [%s]: Unable to retrieve certificate [%s]", message.h.method, message.h.resource.component[3]); + asprintf(&err,"Method [%s]: Unable to retrieve certificate [%s]", message.h.method, message.h.resource.component[3]); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Unable to retrieve certificate.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + } - /* + } else { + methods = ogs_msprintf("%s",OGS_SBI_HTTP_METHOD_POST); + response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_servercertificatesprovisioning_api, app_meta); nf_server_populate_response(response, 0, NULL, 204); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - - if(methods) ogs_free(methods); - */ - } else { - char *err = NULL; - int number_of_components; - const nf_server_interface_metadata_t *interface; - if (message.h.resource.component[2]){ - if (!strcmp(message.h.resource.component[2],"certificates")) { - number_of_components = 2; - if (message.h.resource.component[3]) { - number_of_components = 3; - } - interface = m1_servercertificatesprovisioning_api; - } else if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { - number_of_components = 2; - interface = m1_contenthostingprovisioning_api; - - } - } else if (message.h.resource.component[0]){ - if (!strcmp(message.h.resource.component[0],"provisioning-sessions")){ - number_of_components = 0; - if (message.h.resource.component[1]) { - number_of_components = 1; - } - interface = m1_provisioningsession_api; - - } - } - asprintf(&err,"Method [%s]: [%s] - Provisioning Session [%s] does not exist.", message.h.method, message.h.resource.component[2], message.h.resource.component[1]); - ogs_error("Method [%s]: [%s] - Provisioning Session [%s] does not exist.", message.h.method, message.h.resource.component[2], message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, number_of_components, &message, "Provisioning Session does not exists.", err, NULL, interface, app_meta)); - } - } else { - methods = ogs_msprintf("%s, %s",OGS_SBI_HTTP_METHOD_POST, OGS_SBI_HTTP_METHOD_OPTIONS); - response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_provisioningsession_api, app_meta); + } else if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { + methods = ogs_msprintf("%s, %s, %s, %s, %s",OGS_SBI_HTTP_METHOD_POST, OGS_SBI_HTTP_METHOD_GET, OGS_SBI_HTTP_METHOD_PUT, OGS_SBI_HTTP_METHOD_DELETE, OGS_SBI_HTTP_METHOD_OPTIONS); + response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_contenthostingprovisioning_api, app_meta); nf_server_populate_response(response, 0, NULL, 204); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + } else { + char *err = NULL; + asprintf(&err,"Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[2]); + ogs_error("Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[2]); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Target not yet supported.", err, NULL, NULL, app_meta)); } - if(methods) ogs_free(methods); } else { - char *err = NULL; - asprintf(&err,"Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[0]); - ogs_error("Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[0]); - ogs_assert(true == nf_server_send_error(stream, 404, 0, &message, "Target not yet supported.", err, NULL, m1_provisioningsession_api, app_meta)); - - } - break; - - DEFAULT - ogs_error("Invalid HTTP method [%s]", message.h.method); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 0, &message, "Invalid HTTP method.", message.h.method, NULL, NULL, app_meta)); - - END - break; + methods = ogs_msprintf("%s, %s, %s", OGS_SBI_HTTP_METHOD_GET, OGS_SBI_HTTP_METHOD_DELETE, OGS_SBI_HTTP_METHOD_OPTIONS); + response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_provisioningsession_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + + } + /* + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + + if(methods) ogs_free(methods); + */ + } else { + char *err = NULL; + int number_of_components; + const nf_server_interface_metadata_t *interface; + if (message.h.resource.component[2]){ + if (!strcmp(message.h.resource.component[2],"certificates")) { + number_of_components = 2; + if (message.h.resource.component[3]) { + number_of_components = 3; + } + interface = m1_servercertificatesprovisioning_api; + } else if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { + number_of_components = 2; + interface = m1_contenthostingprovisioning_api; + + } + } else if (message.h.resource.component[0]){ + if (!strcmp(message.h.resource.component[0],"provisioning-sessions")){ + number_of_components = 0; + if (message.h.resource.component[1]) { + number_of_components = 1; + } + interface = m1_provisioningsession_api; + + } + } + asprintf(&err,"Method [%s]: [%s] - Provisioning Session [%s] does not exist.", message.h.method, message.h.resource.component[2], message.h.resource.component[1]); + ogs_error("Method [%s]: [%s] - Provisioning Session [%s] does not exist.", message.h.method, message.h.resource.component[2], message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, number_of_components, &message, "Provisioning Session does not exists.", err, NULL, interface, app_meta)); + + } + + } else { + methods = ogs_msprintf("%s, %s",OGS_SBI_HTTP_METHOD_POST, OGS_SBI_HTTP_METHOD_OPTIONS); + response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_provisioningsession_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + + } + if(methods) ogs_free(methods); + } else { + char *err = NULL; + asprintf(&err,"Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[0]); + ogs_error("Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[0]); + ogs_assert(true == nf_server_send_error(stream, 404, 0, &message, "Target not yet supported.", err, NULL, m1_provisioningsession_api, app_meta)); + + } + break; + + DEFAULT + ogs_error("Invalid HTTP method [%s]", message.h.method); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 0, &message, "Invalid HTTP method.", message.h.method, NULL, NULL, app_meta)); - DEFAULT - char *err; - ogs_error("Invalid resource name [%s]", - message.h.resource.component[0]); - asprintf(&err,"Invalid resource name [%s]", message.h.resource.component[0]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid resource name", err, NULL, NULL, app_meta)); - END + break; + + DEFAULT + char *err; + ogs_error("Invalid resource name [%s]", + message.h.resource.component[0]); + asprintf(&err,"Invalid resource name [%s]", message.h.resource.component[0]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid resource name", err, NULL, NULL, app_meta)); + + END + ogs_sbi_message_free(&message); + break; + + CASE("3gpp-m5") + if (strcmp(message.h.api.version, "v2") != 0) { + char *error; + ogs_error("Not supported version [%s]", message.h.api.version); + + error = ogs_msprintf("Version [%s] not supported", message.h.api.version); + + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL, app_meta)); + ogs_sbi_message_free(&message); + ogs_free(error); + break; + } + SWITCH(message.h.resource.component[0]) + CASE("service-access-information") + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_GET) + cJSON *service_access_information; + msaf_provisioning_session_t *msaf_provisioning_session = NULL; + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + + if(msaf_provisioning_session == NULL) { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] not found.", message.h.resource.component[1]); + ogs_error("Client requested invalid Provisioning Session [%s]", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Provisioning Session not found.", err, NULL, m5_serviceaccessinformation_api, app_meta)); + + } else if (msaf_provisioning_session->serviceAccessInformation) { + service_access_information = msaf_context_retrieve_service_access_information(message.h.resource.component[1]); + if (service_access_information != NULL) { + ogs_sbi_response_t *response; + char *text; + text = cJSON_Print(service_access_information); + response = nf_server_new_response(NULL, "application/json", msaf_provisioning_session->serviceAccessInformationCreated, msaf_provisioning_session->serviceAccessInformationHash, msaf_self()->config.server_response_cache_control->m5_service_access_information_response_max_age, NULL, m5_serviceaccessinformation_api, app_meta); + nf_server_populate_response(response, strlen(text), text, 201); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + cJSON_Delete(service_access_information); + } else { + char *err = NULL; + asprintf(&err,"Service Access Information for the Provisioning Session [%s] not found.", message.h.resource.component[1]); + ogs_error("Client requested invalid Service Access Information for the Provisioning Session [%s]", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL, m5_serviceaccessinformation_api, app_meta)); + - CASE("3gpp-m5") - if (strcmp(message.h.api.version, "v2") != 0) { - char *error; - ogs_error("Not supported version [%s]", message.h.api.version); - - error = ogs_msprintf("Version [%s] not supported", message.h.api.version); - - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL, app_meta)); - - ogs_sbi_message_free(&message); - ogs_free(error); - + } + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] has no Service Access Information associated with it.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] has no Service Access Information associated with it", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL, m5_serviceaccessinformation_api, app_meta)); + + } break; - } - SWITCH(message.h.resource.component[0]) - CASE("service-access-information") - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_GET) - cJSON *service_access_information; - msaf_provisioning_session_t *msaf_provisioning_session = NULL; - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + DEFAULT + ogs_error("Invalid HTTP method [%s]", message.h.method); - if(msaf_provisioning_session == NULL) { - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] not found.", message.h.resource.component[1]); - ogs_error("Client requested invalid Provisioning Session [%s]", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Provisioning Session not found.", err, NULL, m5_serviceaccessinformation_api, app_meta)); - - } else if (msaf_provisioning_session->serviceAccessInformation) { - service_access_information = msaf_context_retrieve_service_access_information(message.h.resource.component[1]); - if (service_access_information != NULL) { - ogs_sbi_response_t *response; - char *text; - text = cJSON_Print(service_access_information); - response = nf_server_new_response(NULL, "application/json", msaf_provisioning_session->serviceAccessInformationCreated, msaf_provisioning_session->serviceAccessInformationHash, msaf_self()->config.server_response_cache_control->m5_service_access_information_response_max_age, NULL, m5_serviceaccessinformation_api, app_meta); - nf_server_populate_response(response, strlen(text), text, 201); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - cJSON_Delete(service_access_information); - } else { - char *err = NULL; - asprintf(&err,"Service Access Information for the Provisioning Session [%s] not found.", message.h.resource.component[1]); - ogs_error("Client requested invalid Service Access Information for the Provisioning Session [%s]", message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL, m5_serviceaccessinformation_api, app_meta)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 1, &message, "Invalid HTTP method.", message.h.method, NULL, NULL, app_meta)); - - } - } else { - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] has no Service Access Information associated with it.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] has no Service Access Information associated with it", message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL, m5_serviceaccessinformation_api, app_meta)); - - } - break; - DEFAULT - ogs_error("Invalid HTTP method [%s]", message.h.method); - - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 1, &message, "Invalid HTTP method.", message.h.method, NULL, NULL, app_meta)); - - END - break; - DEFAULT - ogs_error("Invalid resource name [%s]", - message.h.resource.component[0]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid resource name.", message.h.resource.component[0], NULL, NULL, app_meta)); - END - ogs_sbi_message_free(&message); break; DEFAULT - ogs_error("Invalid API name [%s]", message.h.service.name); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid API name.", message.h.service.name, NULL, NULL, app_meta)); + ogs_error("Invalid resource name [%s]", + message.h.resource.component[0]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid resource name.", message.h.resource.component[0], NULL, NULL, app_meta)); + + END + ogs_sbi_message_free(&message); + break; + DEFAULT + ogs_error("Invalid API name [%s]", message.h.service.name); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid API name.", message.h.service.name, NULL, NULL, app_meta)); END break; @@ -1171,685 +1131,679 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) message.res_status = response->status; SWITCH(message.h.service.name) - CASE("3gpp-m3") - SWITCH(message.h.resource.component[0]) - CASE("content-hosting-configurations") - - msaf_application_server_state_node_t *as_state; - as_state = e->application_server_state; - ogs_assert(as_state); - - if (message.h.resource.component[1] && message.h.resource.component[2]) { - - if (!strcmp(message.h.resource.component[2],"purge")) { - - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_POST) - purge_resource_id_node_t *purge_node = e->purge_node; - - if (response->status == 204 || response->status == 200) { - - purge_resource_id_node_t *content_hosting_cache, *next = NULL; - - if (response->status == 200) { - //parse the int in response body - //Add the integer to purge_node->m1_purge_info->purged_entries_total; - { - ogs_hash_index_t *hi; - for (hi = ogs_hash_first(request->http.headers); - hi; hi = ogs_hash_next(hi)) { - if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { - if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/json")) { - char *err = NULL; - char *type = NULL; - type = (char *)ogs_hash_this_val(hi); - ogs_error("Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); - asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); - - ogs_assert(true == nf_server_send_error(stream, 415, 2, &message, "Provisioning session does not exist.", err, NULL, m3_contenthostingprovisioning_api, app_meta)); - ogs_sbi_message_free(&message); - return; - - - } - } - } - } + CASE("3gpp-m3") + SWITCH(message.h.resource.component[0]) + CASE("content-hosting-configurations") + + msaf_application_server_state_node_t *as_state; + as_state = e->application_server_state; + ogs_assert(as_state); + + if (message.h.resource.component[1] && message.h.resource.component[2]) { + + if (!strcmp(message.h.resource.component[2],"purge")) { - int purged_items_from_as = 0; - cJSON *entry; - cJSON *number_of_cache_entries = cJSON_Parse(response->http.content); - cJSON_ArrayForEach(entry, number_of_cache_entries) { - ogs_debug("Purged entries return %d\n", entry->valueint); - purged_items_from_as = entry->valueint; - - } - purge_node->m1_purge_info->purged_entries_total += purged_items_from_as; - - } - - - ogs_list_for_each_safe(&as_state->purge_content_hosting_cache, next, content_hosting_cache){ - if(purge_node->purge_regex) - { - - if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id) && !strcmp(content_hosting_cache->purge_regex, purge_node->purge_regex)) - break; - } else if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id)) - { - break; + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) + purge_resource_id_node_t *purge_node = e->purge_node; + + if (response->status == 204 || response->status == 200) { + + purge_resource_id_node_t *content_hosting_cache, *next = NULL; + + if (response->status == 200) { + //parse the int in response body + //Add the integer to purge_node->m1_purge_info->purged_entries_total; + { + ogs_hash_index_t *hi; + for (hi = ogs_hash_first(request->http.headers); + hi; hi = ogs_hash_next(hi)) { + if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { + if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/json")) { + char *err = NULL; + char *type = NULL; + type = (char *)ogs_hash_this_val(hi); + ogs_error("Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); + asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); + + ogs_assert(true == nf_server_send_error(stream, 415, 2, &message, "Provisioning session does not exist.", err, NULL, m3_contenthostingprovisioning_api, app_meta)); + ogs_sbi_message_free(&message); + return; } } - if(content_hosting_cache){ - ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); - ogs_debug("M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); - - purge_node->m1_purge_info->refs--; - ogs_debug(" After decrement, M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); - if(!purge_node->m1_purge_info->refs){ - // send M1 response with total from purge_node->m1_purge_info->purged_entries_total - // ogs_free(purge_node->m1_purge_info); - ogs_sbi_response_t *response; - cJSON *purged_entries_total_json = cJSON_CreateNumber(purge_node->m1_purge_info->purged_entries_total); - char *purged_entries_total = cJSON_Print(purged_entries_total_json); - response = ogs_sbi_response_new(); - response->http.content_length = strlen(purged_entries_total); - response->http.content = purged_entries_total; - response->status = 200; - ogs_sbi_header_set(response->http.headers, "Content-Type", "application/json"); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(purge_node->m1_purge_info->m1_stream, response)); - - if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); - if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); - if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); - ogs_free(content_hosting_cache); - } - msaf_application_server_state_log(&as_state->purge_content_hosting_cache, "Purge Content Hosting Cache list"); - - } - } - - - if((response->status == 404) || (response->status == 413) || (response->status == 414) || (response->status == 415) || (response->status == 422) || (response->status == 500) || (response->status == 503)) - { - char *error; - purge_resource_id_node_t *content_hosting_cache, *next = NULL; - cJSON *purge_cache_err = NULL; - if(response->http.content){ - purge_cache_err = cJSON_Parse(response->http.content); - char *txt = cJSON_Print(purge_cache_err); - ogs_debug("txt:%s", txt); - } - - if(response->status == 404) { - - ogs_error("Error message from the Application Server [%s] with response code [%d]: Cache not found\n", as_state->application_server->canonicalHostname, response->status); - } else if(response->status == 413) { - ogs_error("Error message from the Application Server [%s] with response code [%d]: Pay load too large\n", as_state->application_server->canonicalHostname, response->status); - } else if(response->status == 414) { - ogs_error("Error message from the Application Server [%s] with response code [%d]: URI too long\n", as_state->application_server->canonicalHostname, response->status); - } else if(response->status == 415) { - ogs_error("Error message from the Application Server [%s] with response code [%d]: Unsupported media type\n", as_state->application_server->canonicalHostname, response->status); - } else if(response->status == 422) { - ogs_error("Error message from the Application Server [%s] with response code [%d]: Unprocessable Entity\n", as_state->application_server->canonicalHostname, response->status); - } else if(response->status == 500) { - ogs_error("Error message from the Application Server [%s] with response code [%d]: Internal server error\n", as_state->application_server->canonicalHostname, response->status); - } else if(response->status == 503) { - ogs_error("Error message from the Application Server [%s] with response code [%d]: Service Unavailable\n", as_state->application_server->canonicalHostname, response->status); - } else { - - ogs_error("Application Server [%s] sent unrecognised response code [%d]", as_state->application_server->canonicalHostname, response->status); - } - - if (purge_node->purge_regex) { - error = ogs_msprintf("Application Server possibly encountered problem with regex %s", purge_node->purge_regex); - } else { - error = ogs_msprintf("Application Server unable to process the contained instructions"); - } - - - ogs_assert(true == nf_server_send_error( purge_node->m1_purge_info->m1_stream, - response->status, 3, &purge_node->m1_purge_info->m1_message, "Problem occured during cache purge", error, purge_cache_err, m1_contenthostingprovisioning_api, app_meta)); - - ogs_list_for_each_safe(&as_state->purge_content_hosting_cache, next, content_hosting_cache){ - if (purge_node->purge_regex) { - if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id) && !strcmp(content_hosting_cache->purge_regex, purge_node->purge_regex)) { - - ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); - ogs_debug("M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); - if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); - if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); - if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); - ogs_free(content_hosting_cache); - - } - } else if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id)) { - - ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); - ogs_debug("M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); - if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); - if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); - if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); - ogs_free(content_hosting_cache); - - } - } - ogs_free(error); - cJSON_Delete(purge_cache_err); - - } - - next_action_for_application_server(as_state); - break; - END - break; - - } - } else if (message.h.resource.component[1]) { - - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_POST) - - if (response->status == 201) { - - ogs_debug("[%s] Method [%s] with Response [%d] recieved for Content Hosting Configuration [%s]", message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); - - resource_id_node_t *content_hosting_configuration; - ogs_list_for_each(&as_state->upload_content_hosting_configurations,content_hosting_configuration) { - if(!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) - break; } - if(content_hosting_configuration) { + } - ogs_debug("Removing %s from upload_content_hosting_configurations", content_hosting_configuration->state); - ogs_list_remove(&as_state->upload_content_hosting_configurations, content_hosting_configuration); - ogs_debug("Adding %s to current_content_hosting_configurations",content_hosting_configuration->state); - ogs_list_add(as_state->current_content_hosting_configurations, content_hosting_configuration); - } + int purged_items_from_as = 0; + cJSON *entry; + cJSON *number_of_cache_entries = cJSON_Parse(response->http.content); + cJSON_ArrayForEach(entry, number_of_cache_entries) { + ogs_debug("Purged entries return %d\n", entry->valueint); + purged_items_from_as = entry->valueint; } - if(response->status == 405){ - ogs_error("Content Hosting Configuration resource already exist at the specified path\n"); - } - if(response->status == 413){ - ogs_error("Payload too large\n"); - } - if(response->status == 414){ - ogs_error("URI too long\n"); - } - if(response->status == 415){ - ogs_error("Unsupported media type\n"); - } - if(response->status == 500){ - ogs_error("Internal server error\n"); - } - if(response->status == 503){ - ogs_error("Service unavailable\n"); - } - next_action_for_application_server(as_state); - break; - CASE(OGS_SBI_HTTP_METHOD_PUT) - if(response->status == 200 || response->status == 204) { - - ogs_debug("[%s] Method [%s] with Response [%d] recieved for Content Hosting Configuration [%s]", message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); - resource_id_node_t *content_hosting_configuration; - ogs_list_for_each(&as_state->upload_content_hosting_configurations,content_hosting_configuration){ - if(!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) - break; - } - if(content_hosting_configuration) { + purge_node->m1_purge_info->purged_entries_total += purged_items_from_as; - ogs_debug("Removing %s from upload_content_hosting_configurations", content_hosting_configuration->state); - ogs_free(content_hosting_configuration->state); - ogs_list_remove(&as_state->upload_content_hosting_configurations, content_hosting_configuration); - ogs_free(content_hosting_configuration); - } + } - } - if(response->status == 404){ - ogs_error("Not Found\n"); - } - if(response->status == 413){ - ogs_error("Payload too large\n"); - } - if(response->status == 414){ - ogs_error("URI too long\n"); - } - if(response->status == 415){ - ogs_error("Unsupported Media Type\n"); - } - if(response->status == 500){ - ogs_error("Internal Server Error\n"); - } - if(response->status == 503){ - ogs_error("Service Unavailable\n"); - } - next_action_for_application_server(as_state); - break; - CASE(OGS_SBI_HTTP_METHOD_DELETE) - if(response->status == 204) { - ogs_debug("[%s] Method [%s] with Response [%d] recieved for Content Hosting Configuration [%s]", message.h.resource.component[0], message.h.method, response->status,message.h.resource.component[1]); + ogs_list_for_each_safe(&as_state->purge_content_hosting_cache, next, content_hosting_cache){ + if (purge_node->purge_regex) { + if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id) && !strcmp(content_hosting_cache->purge_regex, purge_node->purge_regex)) + break; + } else if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id)) { + break; + } + } + if(content_hosting_cache){ + ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); + ogs_debug("M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); + + purge_node->m1_purge_info->refs--; + ogs_debug(" After decrement, M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); + if(!purge_node->m1_purge_info->refs){ + // send M1 response with total from purge_node->m1_purge_info->purged_entries_total + // ogs_free(purge_node->m1_purge_info); + ogs_sbi_response_t *response; + cJSON *purged_entries_total_json = cJSON_CreateNumber(purge_node->m1_purge_info->purged_entries_total); + char *purged_entries_total = cJSON_Print(purged_entries_total_json); + response = ogs_sbi_response_new(); + response->http.content_length = strlen(purged_entries_total); + response->http.content = purged_entries_total; + response->status = 200; + ogs_sbi_header_set(response->http.headers, "Content-Type", "application/json"); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(purge_node->m1_purge_info->m1_stream, response)); - resource_id_node_t *content_hosting_configuration, *next = NULL; - resource_id_node_t *delete_content_hosting_configuration, *node = NULL; + if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); + if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); + if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); + ogs_free(content_hosting_cache); + } + msaf_application_server_state_log(&as_state->purge_content_hosting_cache, "Purge Content Hosting Cache list"); - if(as_state->current_content_hosting_configurations) { + } + } - ogs_list_for_each_safe(as_state->current_content_hosting_configurations, next, content_hosting_configuration){ - if(!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) - break; - } - } + if((response->status == 404) || (response->status == 413) || (response->status == 414) || (response->status == 415) || (response->status == 422) || (response->status == 500) || (response->status == 503)) { + char *error; + purge_resource_id_node_t *content_hosting_cache, *next = NULL; + cJSON *purge_cache_err = NULL; + if(response->http.content){ + purge_cache_err = cJSON_Parse(response->http.content); + char *txt = cJSON_Print(purge_cache_err); + ogs_debug("txt:%s", txt); + } - if(content_hosting_configuration) { + if(response->status == 404) { + + ogs_error("Error message from the Application Server [%s] with response code [%d]: Cache not found\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 413) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Pay load too large\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 414) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: URI too long\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 415) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Unsupported media type\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 422) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Unprocessable Entity\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 500) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Internal server error\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 503) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Service Unavailable\n", as_state->application_server->canonicalHostname, response->status); + } else { - msaf_application_server_state_log(as_state->current_content_hosting_configurations, "Current Content Hosting Configurations"); + ogs_error("Application Server [%s] sent unrecognised response code [%d]", as_state->application_server->canonicalHostname, response->status); + } - ogs_debug("Removing %s from current_content_hosting_configurations", content_hosting_configuration->state); - ogs_free(content_hosting_configuration->state); - ogs_list_remove(as_state->current_content_hosting_configurations, content_hosting_configuration); - ogs_free(content_hosting_configuration); - msaf_application_server_state_log(as_state->current_content_hosting_configurations, "Current Content Hosting Configurations"); - } + if (purge_node->purge_regex) { + error = ogs_msprintf("Application Server possibly encountered problem with regex %s", purge_node->purge_regex); + } else { + error = ogs_msprintf("Application Server unable to process the contained instructions"); + } - ogs_list_for_each_safe(&as_state->delete_content_hosting_configurations, node, delete_content_hosting_configuration) { - if (!strcmp(delete_content_hosting_configuration->state, message.h.resource.component[1])) { + ogs_assert(true == nf_server_send_error( purge_node->m1_purge_info->m1_stream, + response->status, 3, &purge_node->m1_purge_info->m1_message, "Problem occured during cache purge", error, purge_cache_err, m1_contenthostingprovisioning_api, app_meta)); - msaf_application_server_state_log(&as_state->delete_content_hosting_configurations, "Delete Content Hosting Configurations"); + ogs_list_for_each_safe(&as_state->purge_content_hosting_cache, next, content_hosting_cache){ + if (purge_node->purge_regex) { + if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id) && !strcmp(content_hosting_cache->purge_regex, purge_node->purge_regex)) { - ogs_debug("Destroying Content Hosting Configuration: %s", delete_content_hosting_configuration->state); - ogs_free(delete_content_hosting_configuration->state); - ogs_list_remove(&as_state->delete_content_hosting_configurations, delete_content_hosting_configuration); - ogs_free(delete_content_hosting_configuration); + ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); + ogs_debug("M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); + if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); + if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); + if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); + ogs_free(content_hosting_cache); - msaf_application_server_state_log(&as_state->delete_content_hosting_configurations, "Delete Content Hosting Configurations"); - } } + } else if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id)) { + + ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); + ogs_debug("M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); + if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); + if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); + if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); + ogs_free(content_hosting_cache); } - if(response->status == 404){ - ogs_error("Not Found\n"); - } - if(response->status == 413){ - ogs_error("Payload too large\n"); - } - if(response->status == 414){ - ogs_error("URI too long\n"); - } - if(response->status == 415){ - ogs_error("Unsupported Media Type\n"); - } - if(response->status == 500){ - ogs_error("Internal Server Error\n"); - } - if(response->status == 503){ - ogs_error("Service Unavailable\n"); - } - next_action_for_application_server(as_state); - break; - DEFAULT - ogs_error("Unknown M3 Content Hosting Configuration operation [%s]", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Content Hosting Configuration operation", message.h.resource.component[1], NULL, NULL, app_meta)); - break; - END + } + ogs_free(error); + cJSON_Delete(purge_cache_err); + + } + + next_action_for_application_server(as_state); break; - } else { - cJSON *entry; - cJSON *chc_array = cJSON_Parse(response->http.content); - resource_id_node_t *current_chc; - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_GET) + END + break; - if(response->status == 200) { + } + } else if (message.h.resource.component[1]) { - ogs_debug("[%s] Method [%s] with Response [%d] for Content Hosting Configuration operation [%s]", - message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) - if (as_state->current_content_hosting_configurations == NULL) { - as_state->current_content_hosting_configurations = ogs_calloc(1,sizeof(*as_state->current_content_hosting_configurations)); - ogs_assert(as_state->current_content_hosting_configurations); - ogs_list_init(as_state->current_content_hosting_configurations); + if (response->status == 201) { - } else { - resource_id_node_t *next, *node; - ogs_list_for_each_safe(as_state->current_content_hosting_configurations, next, node) { - ogs_free(node->state); - ogs_list_remove(as_state->current_content_hosting_configurations, node); - ogs_free(node); - } - } - cJSON_ArrayForEach(entry, chc_array) { - char *id = strrchr(entry->valuestring, '/'); - if (id == NULL) { - id = entry->valuestring; - } else { - id++; - } - current_chc = ogs_calloc(1, sizeof(*current_chc)); - current_chc->state = ogs_strdup(id); - ogs_debug("Adding [%s] to the current Content Hosting Configuration list",current_chc->state); - ogs_list_add(as_state->current_content_hosting_configurations, current_chc); - } + ogs_debug("[%s] Method [%s] with Response [%d] recieved for Content Hosting Configuration [%s]", message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); - cJSON_Delete(chc_array); - } - if (response->status == 500){ - ogs_error("Received Internal Server error\n"); - } - if (response->status == 503) { - ogs_error("Service Unavailable\n"); - } - next_action_for_application_server(as_state); + resource_id_node_t *content_hosting_configuration; + ogs_list_for_each(&as_state->upload_content_hosting_configurations,content_hosting_configuration) { + if(!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) break; - DEFAULT - char *err; - ogs_error("Unknown M3 Content Hosting Configuration operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); - asprintf(&err, "Unknown M3 Content Hosting Configuration operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Content Hosting Configuration operation", err, NULL, NULL, app_meta)); - - break; - END - break; + } + if(content_hosting_configuration) { + + ogs_debug("Removing %s from upload_content_hosting_configurations", content_hosting_configuration->state); + ogs_list_remove(&as_state->upload_content_hosting_configurations, content_hosting_configuration); + ogs_debug("Adding %s to current_content_hosting_configurations",content_hosting_configuration->state); + ogs_list_add(as_state->current_content_hosting_configurations, content_hosting_configuration); + } + + } + if(response->status == 405){ + ogs_error("Content Hosting Configuration resource already exist at the specified path\n"); + } + if(response->status == 413){ + ogs_error("Payload too large\n"); + } + if(response->status == 414){ + ogs_error("URI too long\n"); + } + if(response->status == 415){ + ogs_error("Unsupported media type\n"); + } + if(response->status == 500){ + ogs_error("Internal server error\n"); + } + if(response->status == 503){ + ogs_error("Service unavailable\n"); } next_action_for_application_server(as_state); + break; + CASE(OGS_SBI_HTTP_METHOD_PUT) + if(response->status == 200 || response->status == 204) { + + ogs_debug("[%s] Method [%s] with Response [%d] recieved for Content Hosting Configuration [%s]", message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); + resource_id_node_t *content_hosting_configuration; + ogs_list_for_each(&as_state->upload_content_hosting_configurations,content_hosting_configuration){ + if(!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) + break; + } + if(content_hosting_configuration) { + + ogs_debug("Removing %s from upload_content_hosting_configurations", content_hosting_configuration->state); + ogs_free(content_hosting_configuration->state); + ogs_list_remove(&as_state->upload_content_hosting_configurations, content_hosting_configuration); + ogs_free(content_hosting_configuration); + } + } + if(response->status == 404){ + ogs_error("Not Found\n"); + } + if(response->status == 413){ + ogs_error("Payload too large\n"); + } + if(response->status == 414){ + ogs_error("URI too long\n"); + } + if(response->status == 415){ + ogs_error("Unsupported Media Type\n"); + } + if(response->status == 500){ + ogs_error("Internal Server Error\n"); + } + if(response->status == 503){ + ogs_error("Service Unavailable\n"); + } + next_action_for_application_server(as_state); break; + CASE(OGS_SBI_HTTP_METHOD_DELETE) + if(response->status == 204) { - CASE("certificates") + ogs_debug("[%s] Method [%s] with Response [%d] recieved for Content Hosting Configuration [%s]", message.h.resource.component[0], message.h.method, response->status,message.h.resource.component[1]); - msaf_application_server_state_node_t *as_state; - as_state = e->application_server_state; - ogs_assert(as_state); - if (message.h.resource.component[1]) { - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_POST) - if(response->status == 201) { + resource_id_node_t *content_hosting_configuration, *next = NULL; + resource_id_node_t *delete_content_hosting_configuration, *node = NULL; - ogs_debug("[%s] Method [%s] with Response [%d] recieved for certificate [%s]", message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); + if(as_state->current_content_hosting_configurations) { - resource_id_node_t *certificate; + ogs_list_for_each_safe(as_state->current_content_hosting_configurations, next, content_hosting_configuration){ - //Iterate upload_certs and find match strcmp resource component 0 - ogs_list_for_each(&as_state->upload_certificates,certificate){ - if(!strcmp(certificate->state, message.h.resource.component[1])) - break; - } - if(certificate) { + if(!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) + break; + } + } - ogs_debug("Removing certificate [%s] from upload_certificates", certificate->state); + if(content_hosting_configuration) { - ogs_list_remove(&as_state->upload_certificates, certificate); + msaf_application_server_state_log(as_state->current_content_hosting_configurations, "Current Content Hosting Configurations"); - ogs_debug("Adding certificate [%s] to current_certificates", certificate->state); + ogs_debug("Removing %s from current_content_hosting_configurations", content_hosting_configuration->state); + ogs_free(content_hosting_configuration->state); + ogs_list_remove(as_state->current_content_hosting_configurations, content_hosting_configuration); + ogs_free(content_hosting_configuration); + msaf_application_server_state_log(as_state->current_content_hosting_configurations, "Current Content Hosting Configurations"); + } - ogs_list_add(as_state->current_certificates, certificate); - // ogs_free(upload_cert_id); - } - } - if(response->status == 405){ - ogs_error("Server Certificate resource already exist at the specified path\n"); - } - if(response->status == 413){ - ogs_error("Payload too large\n"); - } - if(response->status == 414){ - ogs_error("URI too long\n"); - } - if(response->status == 415){ - ogs_error("Unsupported media type\n"); - } - if(response->status == 500){ - ogs_error("Internal server error\n"); - } - if(response->status == 503){ - ogs_error("Service unavailable\n"); - } - next_action_for_application_server(as_state); - break; - CASE(OGS_SBI_HTTP_METHOD_PUT) - if(response->status == 200 || response->status == 204) { + ogs_list_for_each_safe(&as_state->delete_content_hosting_configurations, node, delete_content_hosting_configuration) { - ogs_debug("[%s] Method [%s] with Response [%d] recieved for certificate [%s]", message.h.resource.component[0], message.h.method, response->status,message.h.resource.component[1]); + if (!strcmp(delete_content_hosting_configuration->state, message.h.resource.component[1])) { - resource_id_node_t *certificate; + msaf_application_server_state_log(&as_state->delete_content_hosting_configurations, "Delete Content Hosting Configurations"); - msaf_application_server_state_log(&as_state->upload_certificates, "Upload Certificates"); + ogs_debug("Destroying Content Hosting Configuration: %s", delete_content_hosting_configuration->state); + ogs_free(delete_content_hosting_configuration->state); + ogs_list_remove(&as_state->delete_content_hosting_configurations, delete_content_hosting_configuration); + ogs_free(delete_content_hosting_configuration); - //Iterate upload_certs and find match strcmp resource component 0 - ogs_list_for_each(&as_state->upload_certificates,certificate){ + msaf_application_server_state_log(&as_state->delete_content_hosting_configurations, "Delete Content Hosting Configurations"); + } + } - if(!strcmp(certificate->state, message.h.resource.component[1])) - break; - } + } + if(response->status == 404){ + ogs_error("Not Found\n"); + } + if(response->status == 413){ + ogs_error("Payload too large\n"); + } + if(response->status == 414){ + ogs_error("URI too long\n"); + } + if(response->status == 415){ + ogs_error("Unsupported Media Type\n"); + } + if(response->status == 500){ + ogs_error("Internal Server Error\n"); + } + if(response->status == 503){ + ogs_error("Service Unavailable\n"); + } + next_action_for_application_server(as_state); + break; + DEFAULT + ogs_error("Unknown M3 Content Hosting Configuration operation [%s]", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Content Hosting Configuration operation", message.h.resource.component[1], NULL, NULL, app_meta)); + break; + END + break; + } else { + cJSON *entry; + cJSON *chc_array = cJSON_Parse(response->http.content); + resource_id_node_t *current_chc; + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_GET) + + if(response->status == 200) { + + ogs_debug("[%s] Method [%s] with Response [%d] for Content Hosting Configuration operation [%s]", + message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); + + if (as_state->current_content_hosting_configurations == NULL) { + as_state->current_content_hosting_configurations = ogs_calloc(1,sizeof(*as_state->current_content_hosting_configurations)); + ogs_assert(as_state->current_content_hosting_configurations); + ogs_list_init(as_state->current_content_hosting_configurations); + + } else { + resource_id_node_t *next, *node; + ogs_list_for_each_safe(as_state->current_content_hosting_configurations, next, node) { + ogs_free(node->state); + ogs_list_remove(as_state->current_content_hosting_configurations, node); + ogs_free(node); + } + } + cJSON_ArrayForEach(entry, chc_array) { + char *id = strrchr(entry->valuestring, '/'); + if (id == NULL) { + id = entry->valuestring; + } else { + id++; + } + current_chc = ogs_calloc(1, sizeof(*current_chc)); + current_chc->state = ogs_strdup(id); + ogs_debug("Adding [%s] to the current Content Hosting Configuration list",current_chc->state); + ogs_list_add(as_state->current_content_hosting_configurations, current_chc); + } - if(!certificate){ - ogs_debug("Certificate %s not found in upload certificates", message.h.resource.component[1]); - } else { - ogs_debug("Removing certificate [%s] from upload_certificates", certificate->state); - ogs_free(certificate->state); + cJSON_Delete(chc_array); + } + if (response->status == 500){ + ogs_error("Received Internal Server error\n"); + } + if (response->status == 503) { + ogs_error("Service Unavailable\n"); + } + next_action_for_application_server(as_state); + break; + DEFAULT + char *err; + ogs_error("Unknown M3 Content Hosting Configuration operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + asprintf(&err, "Unknown M3 Content Hosting Configuration operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Content Hosting Configuration operation", err, NULL, NULL, app_meta)); - ogs_list_remove(&as_state->upload_certificates, certificate); - ogs_free(certificate); - } - } - if(response->status == 404){ - ogs_error("Not Found\n"); - } - if(response->status == 413){ - ogs_error("Payload too large\n"); - } - if(response->status == 414){ - ogs_error("URI too long\n"); - } - if(response->status == 415){ - ogs_error("Unsupported Media Type\n"); - } - if(response->status == 500){ - ogs_error("Internal Server Error\n"); - } - if(response->status == 503){ - ogs_error("Service Unavailable\n"); - } - next_action_for_application_server(as_state); - break; - CASE(OGS_SBI_HTTP_METHOD_DELETE) - if(response->status == 204) { + break; + END + break; + } + next_action_for_application_server(as_state); - ogs_debug("[%s] Method [%s] with Response [%d] recieved for Certificate [%s]", message.h.resource.component[0], message.h.method, response->status,message.h.resource.component[1]); + break; - resource_id_node_t *certificate, *next = NULL; - resource_id_node_t *delete_certificate, *node = NULL; + CASE("certificates") - if(as_state->current_certificates) { - ogs_list_for_each_safe(as_state->current_certificates, next, certificate){ + msaf_application_server_state_node_t *as_state; + as_state = e->application_server_state; + ogs_assert(as_state); + if (message.h.resource.component[1]) { + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) + if(response->status == 201) { - if(!strcmp(certificate->state, message.h.resource.component[1])) - break; - } - } + ogs_debug("[%s] Method [%s] with Response [%d] recieved for certificate [%s]", message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); - if(certificate) { + resource_id_node_t *certificate; - msaf_application_server_state_log(as_state->current_certificates, "Current Certificates"); + //Iterate upload_certs and find match strcmp resource component 0 + ogs_list_for_each(&as_state->upload_certificates,certificate){ + if(!strcmp(certificate->state, message.h.resource.component[1])) + break; + } + if(certificate) { - ogs_debug("Removing certificate [%s] from current_certificates", certificate->state); - ogs_free(certificate->state); + ogs_debug("Removing certificate [%s] from upload_certificates", certificate->state); - ogs_list_remove(as_state->current_certificates, certificate); - ogs_free(certificate); - msaf_application_server_state_log(as_state->current_certificates, "Current Certificates"); - } + ogs_list_remove(&as_state->upload_certificates, certificate); + ogs_debug("Adding certificate [%s] to current_certificates", certificate->state); - ogs_list_for_each_safe(&as_state->delete_certificates, node, delete_certificate){ + ogs_list_add(as_state->current_certificates, certificate); + // ogs_free(upload_cert_id); + } + } + if(response->status == 405){ + ogs_error("Server Certificate resource already exist at the specified path\n"); + } + if(response->status == 413){ + ogs_error("Payload too large\n"); + } + if(response->status == 414){ + ogs_error("URI too long\n"); + } + if(response->status == 415){ + ogs_error("Unsupported media type\n"); + } + if(response->status == 500){ + ogs_error("Internal server error\n"); + } + if(response->status == 503){ + ogs_error("Service unavailable\n"); + } + next_action_for_application_server(as_state); + break; + CASE(OGS_SBI_HTTP_METHOD_PUT) + if(response->status == 200 || response->status == 204) { - if(!strcmp(delete_certificate->state, message.h.resource.component[1])) { - msaf_application_server_state_log(&as_state->delete_certificates, "Delete Certificates"); + ogs_debug("[%s] Method [%s] with Response [%d] recieved for certificate [%s]", message.h.resource.component[0], message.h.method, response->status,message.h.resource.component[1]); - ogs_debug("Destroying Certificate: %s", delete_certificate->state); - ogs_free(delete_certificate->state); - ogs_list_remove(&as_state->delete_certificates, delete_certificate); - ogs_free(delete_certificate); - msaf_application_server_state_log(&as_state->delete_certificates, "Delete Certificates"); + resource_id_node_t *certificate; - } - } - } - if(response->status == 404){ - ogs_error("Not Found\n"); - } - if(response->status == 413){ - ogs_error("Payload too large\n"); - } - if(response->status == 414){ - ogs_error("URI too long\n"); - } - if(response->status == 415){ - ogs_error("Unsupported Media Type\n"); - } - if(response->status == 500){ - ogs_error("Internal Server Error\n"); - } - if(response->status == 503){ - ogs_error("Service Unavailable\n"); - } - next_action_for_application_server(as_state); - break; - DEFAULT - ogs_error("Unknown M3 certificate operation [%s]", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 certificate operation.", message.h.resource.component[1], NULL, NULL, app_meta)); + msaf_application_server_state_log(&as_state->upload_certificates, "Upload Certificates"); + + //Iterate upload_certs and find match strcmp resource component 0 + ogs_list_for_each(&as_state->upload_certificates,certificate){ + + if(!strcmp(certificate->state, message.h.resource.component[1])) break; - END - break; - } else { - cJSON *entry; - cJSON *cert_array = cJSON_Parse(response->http.content); - resource_id_node_t *current_cert; - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_GET) + } - if(response->status == 200) { + if(!certificate){ + ogs_debug("Certificate %s not found in upload certificates", message.h.resource.component[1]); + } else { + ogs_debug("Removing certificate [%s] from upload_certificates", certificate->state); + ogs_free(certificate->state); - ogs_debug("[%s] Method [%s] with Response [%d] received", - message.h.resource.component[0], message.h.method, response->status); + ogs_list_remove(&as_state->upload_certificates, certificate); + ogs_free(certificate); + } + } + if(response->status == 404){ + ogs_error("Not Found\n"); + } + if(response->status == 413){ + ogs_error("Payload too large\n"); + } + if(response->status == 414){ + ogs_error("URI too long\n"); + } + if(response->status == 415){ + ogs_error("Unsupported Media Type\n"); + } + if(response->status == 500){ + ogs_error("Internal Server Error\n"); + } + if(response->status == 503){ + ogs_error("Service Unavailable\n"); + } + next_action_for_application_server(as_state); + break; + CASE(OGS_SBI_HTTP_METHOD_DELETE) + if(response->status == 204) { - if (as_state->current_certificates == NULL) { - as_state->current_certificates = ogs_calloc(1,sizeof(*as_state->current_certificates)); - ogs_assert(as_state->current_certificates); - ogs_list_init(as_state->current_certificates); + ogs_debug("[%s] Method [%s] with Response [%d] recieved for Certificate [%s]", message.h.resource.component[0], message.h.method, response->status,message.h.resource.component[1]); - } else { - resource_id_node_t *next, *node; - ogs_list_for_each_safe(as_state->current_certificates, next, node) { + resource_id_node_t *certificate, *next = NULL; + resource_id_node_t *delete_certificate, *node = NULL; - ogs_debug("Removing certificate [%s] from current_certificates", node->state); + if(as_state->current_certificates) { + ogs_list_for_each_safe(as_state->current_certificates, next, certificate){ - ogs_free(node->state); - ogs_list_remove(as_state->current_certificates, node); - ogs_free(node); - } - } - cJSON_ArrayForEach(entry, cert_array) { - char *id = strrchr(entry->valuestring, '/'); - if (id == NULL) { - id = entry->valuestring; - } else { - id++; - } - current_cert = ogs_calloc(1, sizeof(*current_cert)); - current_cert->state = ogs_strdup(id); - ogs_debug("Adding certificate [%s] to Current certificates", current_cert->state); - ogs_list_add(as_state->current_certificates, current_cert); - } + if(!strcmp(certificate->state, message.h.resource.component[1])) + break; + } + } - cJSON_Delete(cert_array); - } - if (response->status == 500){ - ogs_error("Received Internal Server error"); - } - if (response->status == 503) { - ogs_error("Service Unavailable"); - } - next_action_for_application_server(as_state); - break; - DEFAULT - char *err; - ogs_error("Unknown M3 certificate operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); - asprintf(&err, "Unsupported M3 Certificate operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Certificate operation", err, NULL, NULL, app_meta)); - - break; - END - break; + if(certificate) { + + msaf_application_server_state_log(as_state->current_certificates, "Current Certificates"); + + ogs_debug("Removing certificate [%s] from current_certificates", certificate->state); + ogs_free(certificate->state); + + ogs_list_remove(as_state->current_certificates, certificate); + ogs_free(certificate); + msaf_application_server_state_log(as_state->current_certificates, "Current Certificates"); + } + + + ogs_list_for_each_safe(&as_state->delete_certificates, node, delete_certificate){ + + if(!strcmp(delete_certificate->state, message.h.resource.component[1])) { + msaf_application_server_state_log(&as_state->delete_certificates, "Delete Certificates"); + + ogs_debug("Destroying Certificate: %s", delete_certificate->state); + ogs_free(delete_certificate->state); + ogs_list_remove(&as_state->delete_certificates, delete_certificate); + ogs_free(delete_certificate); + msaf_application_server_state_log(&as_state->delete_certificates, "Delete Certificates"); + + } + } + } + if(response->status == 404){ + ogs_error("Not Found\n"); + } + if(response->status == 413){ + ogs_error("Payload too large\n"); + } + if(response->status == 414){ + ogs_error("URI too long\n"); + } + if(response->status == 415){ + ogs_error("Unsupported Media Type\n"); + } + if(response->status == 500){ + ogs_error("Internal Server Error\n"); + } + if(response->status == 503){ + ogs_error("Service Unavailable\n"); } next_action_for_application_server(as_state); - break; - DEFAULT - ogs_error("Unknown M3 operation [%s]", message.h.resource.component[0]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unsupported M3 operation", message.h.resource.component[0], NULL, NULL, app_meta)); + ogs_error("Unknown M3 certificate operation [%s]", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 certificate operation.", message.h.resource.component[1], NULL, NULL, app_meta)); break; - END - break; + END + break; + } else { + cJSON *entry; + cJSON *cert_array = cJSON_Parse(response->http.content); + resource_id_node_t *current_cert; + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_GET) - CASE(OGS_SBI_SERVICE_NAME_NNRF_NFM) + if(response->status == 200) { - SWITCH(message.h.resource.component[0]) - CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES) - nf_instance = e->h.sbi.data; - ogs_assert(nf_instance); - ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); + ogs_debug("[%s] Method [%s] with Response [%d] received", + message.h.resource.component[0], message.h.method, response->status); - e->h.sbi.message = &message; - ogs_fsm_dispatch(&nf_instance->sm, e); - break; + if (as_state->current_certificates == NULL) { + as_state->current_certificates = ogs_calloc(1,sizeof(*as_state->current_certificates)); + ogs_assert(as_state->current_certificates); + ogs_list_init(as_state->current_certificates); - CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS) - subscription_data = e->h.sbi.data; - ogs_assert(subscription_data); + } else { + resource_id_node_t *next, *node; + ogs_list_for_each_safe(as_state->current_certificates, next, node) { - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_POST) - if (message.res_status == OGS_SBI_HTTP_STATUS_CREATED || - message.res_status == OGS_SBI_HTTP_STATUS_OK) { - ogs_nnrf_nfm_handle_nf_status_subscribe( - subscription_data, &message); - } else { - ogs_error("HTTP response error : %d", - message.res_status); - } - break; + ogs_debug("Removing certificate [%s] from current_certificates", node->state); - CASE(OGS_SBI_HTTP_METHOD_DELETE) - if (message.res_status == OGS_SBI_HTTP_STATUS_NO_CONTENT) { - ogs_sbi_subscription_data_remove(subscription_data); + ogs_free(node->state); + ogs_list_remove(as_state->current_certificates, node); + ogs_free(node); + } + } + cJSON_ArrayForEach(entry, cert_array) { + char *id = strrchr(entry->valuestring, '/'); + if (id == NULL) { + id = entry->valuestring; } else { - ogs_error("HTTP response error : %d", - message.res_status); + id++; } - break; + current_cert = ogs_calloc(1, sizeof(*current_cert)); + current_cert->state = ogs_strdup(id); + ogs_debug("Adding certificate [%s] to Current certificates", current_cert->state); + ogs_list_add(as_state->current_certificates, current_cert); + } - DEFAULT - ogs_error("Invalid HTTP method [%s]", message.h.method); - ogs_assert_if_reached(); - END + cJSON_Delete(cert_array); + } + if (response->status == 500){ + ogs_error("Received Internal Server error"); + } + if (response->status == 503) { + ogs_error("Service Unavailable"); + } + next_action_for_application_server(as_state); break; - DEFAULT - ogs_error("Invalid resource name [%s]", - message.h.resource.component[0]); - ogs_assert_if_reached(); + char *err; + ogs_error("Unknown M3 certificate operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + asprintf(&err, "Unsupported M3 Certificate operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Certificate operation", err, NULL, NULL, app_meta)); + + break; + END + break; + } + next_action_for_application_server(as_state); + + break; + + DEFAULT + ogs_error("Unknown M3 operation [%s]", message.h.resource.component[0]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unsupported M3 operation", message.h.resource.component[0], NULL, NULL, app_meta)); + break; + END + break; + + CASE(OGS_SBI_SERVICE_NAME_NNRF_NFM) + + SWITCH(message.h.resource.component[0]) + CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES) + nf_instance = e->h.sbi.data; + ogs_assert(nf_instance); + ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); + + e->h.sbi.message = &message; + ogs_fsm_dispatch(&nf_instance->sm, e); + break; + + CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS) + subscription_data = e->h.sbi.data; + ogs_assert(subscription_data); + + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) + if (message.res_status == OGS_SBI_HTTP_STATUS_CREATED || + message.res_status == OGS_SBI_HTTP_STATUS_OK) { + ogs_nnrf_nfm_handle_nf_status_subscribe( + subscription_data, &message); + } else { + ogs_error("HTTP response error : %d", + message.res_status); + } + break; + + CASE(OGS_SBI_HTTP_METHOD_DELETE) + if (message.res_status == OGS_SBI_HTTP_STATUS_NO_CONTENT) { + ogs_sbi_subscription_data_remove(subscription_data); + } else { + ogs_error("HTTP response error : %d", + message.res_status); + } + break; + + DEFAULT + ogs_error("Invalid HTTP method [%s]", message.h.method); + ogs_assert_if_reached(); END break; DEFAULT - ogs_error("Invalid service name [%s]", message.h.service.name); + ogs_error("Invalid resource name [%s]", + message.h.resource.component[0]); ogs_assert_if_reached(); + END + break; + + DEFAULT + ogs_error("Invalid service name [%s]", message.h.service.name); + ogs_assert_if_reached(); END ogs_sbi_message_free(&message); @@ -1914,3 +1868,6 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } ogs_free(nf_name); } + +/* vim:ts=8:sts=4:sw=4:expandtab: +*/ diff --git a/src/5gmsaf/msaf.yaml b/src/5gmsaf/msaf.yaml.in similarity index 91% rename from src/5gmsaf/msaf.yaml rename to src/5gmsaf/msaf.yaml.in index 789fb15..6ec457c 100644 --- a/src/5gmsaf/msaf.yaml +++ b/src/5gmsaf/msaf.yaml.in @@ -139,18 +139,14 @@ msaf: - canonicalHostname: localhost urlPathPrefixFormat: /m4d/provisioning-session-{provisioningSessionId}/ m3Port: 7777 - certificateManager: ./certmgr + certificateManager: @default-certmgr@ serverResponseCacheControl: - - maxAge: 61 - m1ProvisioningSessions: 62 - m1ContentHostingConfigurations: 63 - m1ServerCertificates: 65 + - maxAge: 60 + m1ProvisioningSessions: 60 + m1ContentHostingConfigurations: 60 + m1ServerCertificates: 60 m1ContentProtocols: 86400 - m5ServiceAccessInformation: 64 - # The following parameters are only needed for MVP#2 and will be automated - # in future. - certificate: ../../examples/Certificates.json - contentHostingConfiguration: ../../examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_http_and_https.json + m5ServiceAccessInformation: 60 # # nrf: # diff --git a/src/5gmsaf/provisioning-session.c b/src/5gmsaf/provisioning-session.c index 2c76457..f28d081 100644 --- a/src/5gmsaf/provisioning-session.c +++ b/src/5gmsaf/provisioning-session.c @@ -27,8 +27,8 @@ static int ogs_hash_do_cert_check(void *rec, const void *key, int klen, const vo static int free_ogs_hash_provisioning_session(void *rec, const void *key, int klen, const void *value); static char* url_path_create(const char* macro, const char* session_id, const msaf_application_server_node_t *msaf_as); static void tidy_relative_path_re(void); -static char *calculate_provisioning_session_hash(OpenAPI_provisioning_session_t *provisioning_session); -static char *calculate_service_access_information_hash(OpenAPI_service_access_information_resource_t *service_access_information); +static const char *calculate_provisioning_session_hash(OpenAPI_provisioning_session_t *provisioning_session); +static const char *calculate_service_access_information_hash(OpenAPI_service_access_information_resource_t *service_access_information); /***** Public functions *****/ @@ -289,28 +289,7 @@ msaf_provisioning_session_find_by_provisioningSessionId(const char *provisioning ogs_hash_t * msaf_certificate_map(void) { - cJSON *entry; ogs_hash_t *certificate_map = ogs_hash_make(); - char *certificate = read_file(msaf_self()->config.certificate); - if(!certificate){ - ogs_error("The certificates JSON file [%s] cannot be opened or read.", msaf_self()->config.certificate); - } - cJSON *cert = cJSON_Parse(certificate); - if (!cert) { - ogs_error("The certificates JSON file [%s] does not parse as JSON.", msaf_self()->config.certificate); - } - cJSON_ArrayForEach(entry, cert) { - char *abs_path; - if (!entry->valuestring) { - ogs_error("Certificates JSON file configuration parameter has not been set"); - continue; - } - abs_path = rebase_path(msaf_self()->config.certificate, entry->valuestring); - ogs_hash_set(certificate_map, ogs_strdup(entry->string), OGS_HASH_KEY_STRING, abs_path); - } - cJSON_Delete(entry); - cJSON_Delete(cert); - free(certificate); return certificate_map; } @@ -353,14 +332,15 @@ msaf_retrieve_certificates_from_map(msaf_provisioning_session_t *provisioning_se certificate->state = provisioning_session_id_plus_cert_id; ogs_list_add(certs, certificate); } else { - ogs_error("Certificate id [%s] not found for Content Hosting Configuration [%s]", dist_config->certificate_id, provisioning_session->provisioningSessionId); + ogs_warn("Certificate id [%s] not found for Content Hosting Configuration [%s]", dist_config->certificate_id, provisioning_session->provisioningSessionId); resource_id_node_t *next; ogs_list_for_each_safe(certs, next, certificate) { ogs_list_remove(certs, certificate); if (certificate->state) ogs_free(certificate->state); ogs_free(certificate); } - certs = NULL; + ogs_free(certs); + certs = NULL; break; } } @@ -467,92 +447,6 @@ cJSON *msaf_get_content_hosting_configuration_by_provisioning_session_id(char *p return content_hosting_configuration_json; } - -OpenAPI_content_hosting_configuration_t * -msaf_content_hosting_configuration_create(msaf_provisioning_session_t *provisioning_session) -{ - OpenAPI_lnode_t *dist_config_node = NULL; - OpenAPI_distribution_configuration_t *dist_config = NULL; - char *url_path; - static const char macro[] = "{provisioningSessionId}"; - msaf_application_server_state_node_t *as_state; - char *domain_name; - - if(!msaf_self()->config.contentHostingConfiguration) { - ogs_error("contentHostingConfiguration not present in the MSAF configuration file"); - } - - ogs_assert(msaf_self()->config.contentHostingConfiguration); - - as_state = ogs_list_first(&msaf_self()->application_server_states); - - url_path = url_path_create(macro, provisioning_session->provisioningSessionId, as_state->application_server); - - char *content_host_config_data = read_file(msaf_self()->config.contentHostingConfiguration); - if (content_host_config_data == NULL){ - ogs_error("Reading contentHostingConfiguration failed"); - } - - ogs_assert(content_host_config_data); - - cJSON *content_host_config_json = cJSON_Parse(content_host_config_data); - - if (content_host_config_json == NULL){ - ogs_error("Parsing contentHostingConfiguration to JSON structure failed"); - } - - ogs_assert(content_host_config_json); - - OpenAPI_content_hosting_configuration_t *content_hosting_configuration - = OpenAPI_content_hosting_configuration_parseFromJSON(content_host_config_json); - if (!uri_relative_check(content_hosting_configuration->entry_point_path)) { - cJSON_Delete(content_host_config_json); - ogs_free(url_path); - ogs_debug("Check for relative URI for entryPointPath fails"); - if (content_hosting_configuration) - OpenAPI_content_hosting_configuration_free(content_hosting_configuration); - ogs_free(content_host_config_data); - return NULL; - } - - if (content_hosting_configuration->distribution_configurations) { - OpenAPI_list_for_each(content_hosting_configuration->distribution_configurations, dist_config_node) { - char *protocol = "http"; - dist_config = (OpenAPI_distribution_configuration_t*)dist_config_node->data; - if (dist_config->canonical_domain_name) - ogs_free(dist_config->canonical_domain_name); - dist_config->canonical_domain_name = ogs_strdup(as_state->application_server->canonicalHostname); - if (dist_config->certificate_id) { - protocol = "https"; - } - - if(dist_config->domain_name_alias){ - domain_name = dist_config->domain_name_alias; - } else { - domain_name = dist_config->canonical_domain_name; - } - - if (dist_config->base_url) - ogs_free(dist_config->base_url); - dist_config->base_url = ogs_msprintf("%s://%s%s", protocol, domain_name, url_path); - ogs_debug("Distribution URL: %s",dist_config->base_url); - } - } else { - ogs_error("The Content Hosting Configuration has no Distribution Configuration"); - if (content_hosting_configuration) - OpenAPI_content_hosting_configuration_free(content_hosting_configuration); - ogs_free(content_host_config_data); - return NULL; - } - - cJSON_Delete(content_host_config_json); - ogs_free(url_path); - free (content_host_config_data); - provisioning_session->contentHostingConfiguration = content_hosting_configuration; - msaf_application_server_state_set(as_state, provisioning_session); - return content_hosting_configuration; -} - void msaf_provisioning_session_hash_remove(char *provisioning_session_id) { @@ -608,11 +502,11 @@ int uri_relative_check(char *entry_point_path) /***** Private functions *****/ -static char *calculate_provisioning_session_hash(OpenAPI_provisioning_session_t *provisioning_session) +static const char *calculate_provisioning_session_hash(OpenAPI_provisioning_session_t *provisioning_session) { cJSON *provisioning_sess = NULL; char *provisioning_session_to_hash; - char *provisioning_session_hashed = NULL; + const char *provisioning_session_hashed = NULL; provisioning_sess = OpenAPI_provisioning_session_convertToJSON(provisioning_session); provisioning_session_to_hash = cJSON_Print(provisioning_sess); cJSON_Delete(provisioning_sess); @@ -621,15 +515,15 @@ static char *calculate_provisioning_session_hash(OpenAPI_provisioning_session_t return provisioning_session_hashed; } -static char *calculate_service_access_information_hash(OpenAPI_service_access_information_resource_t *service_access_information) +static const char *calculate_service_access_information_hash(OpenAPI_service_access_information_resource_t *service_access_information) { cJSON *service_access_info = NULL; char *service_access_information_to_hash; - char *service_access_information_hashed = NULL; + const char *service_access_information_hashed = NULL; service_access_info = OpenAPI_service_access_information_resource_convertToJSON(service_access_information); service_access_information_to_hash = cJSON_Print(service_access_info); cJSON_Delete(service_access_info); - service_access_information_hashed = calculate_hash(service_access_information_to_hash); + service_access_information_hashed = calculate_hash(service_access_information_to_hash); ogs_free(service_access_information_to_hash); return service_access_information_hashed; } diff --git a/src/5gmsaf/utilities.c b/src/5gmsaf/utilities.c index 167c444..b0831ac 100644 --- a/src/5gmsaf/utilities.c +++ b/src/5gmsaf/utilities.c @@ -8,6 +8,10 @@ program. If this file is missing then the license can be retrieved from https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + #include #include #include @@ -15,24 +19,11 @@ program. If this file is missing then the license can be retrieved from #include #include #include -#include "utilities.h" - -void without_spaces(char *return_str, const char *in_str) -{ - while (*in_str != '\0') - { - if(!isspace(*in_str)) - { - *return_str = *in_str; - return_str++; - } - in_str++; - } - *return_str = '\0'; -} +#include +#include "utilities.h" -time_t str_to_time(char *str_time) +time_t str_to_time(const char *str_time) { static time_t time; struct tm tm = {0}; @@ -41,7 +32,7 @@ time_t str_to_time(char *str_time) return time; } -char *get_time(time_t time_epoch) +const char *get_time(time_t time_epoch) { struct tm *ts; static char buf[80]; @@ -148,16 +139,5 @@ uint16_t ascii_to_uint16(const char *str) return ret; } -cJSON *create_cjson_number_object(char *name, int value) -{ - cJSON *item = NULL; - item = cJSON_CreateObject(); - if (cJSON_AddNumberToObject(item, name, value) == NULL) - { - ogs_error("Failed to create JSON object [%s] for integer value [%d]", name, value); - } - return item; -} - /* vim:ts=8:sts=4:sw=4:expandtab: */ diff --git a/src/5gmsaf/utilities.h b/src/5gmsaf/utilities.h index 1e987a8..eae8457 100644 --- a/src/5gmsaf/utilities.h +++ b/src/5gmsaf/utilities.h @@ -1,18 +1,24 @@ /* -License: 5G-MAG Public License (v1.0) -Author: Dev Audsin -Copyright: (C) 2022 British Broadcasting Corporation - -For full license terms please see the LICENSE file distributed with this -program. If this file is missing then the license can be retrieved from -https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view -*/ + * License: 5G-MAG Public License (v1.0) + * Author: Dev Audsin + * Copyright: (C) 2022 British Broadcasting Corporation + * + * For full license terms please see the LICENSE file distributed with this + * program. If this file is missing then the license can be retrieved from + * https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view + */ #ifndef MSAF_UTILITIES_H #define MSAF_UTILITIES_H +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include + +#ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE -#define __USE_XOPEN +#endif #include #include @@ -31,9 +37,8 @@ extern char *rebase_path(const char *base, const char *file); extern long int ascii_to_long(const char *str); extern uint16_t ascii_to_uint16(const char *str); extern int str_match(const char *line, const char *word_to_find); -extern char *get_time(time_t time_epoch); -extern time_t str_to_time(char *str_time); -extern void without_spaces(char *return_str, const char *in_str); +extern const char *get_time(time_t time_epoch); +extern time_t str_to_time(const char *str_time); #ifdef __cplusplus } diff --git a/tools/bash/certmgr b/tools/bash/certmgr new file mode 100755 index 0000000..a3996b8 --- /dev/null +++ b/tools/bash/certmgr @@ -0,0 +1,434 @@ +#!/bin/bash +# +# 5G-MAG Reference Tools: Certificate Management script +# ====================================================== +# +# License: 5G-MAG Public License v1.0 +# Authors: Dev Audsin +# David Waring +# Copyright: ©2023 British Broadcasting Corporation +# +# For full license terms please see the LICENSE file distributed with this +# program. If this file is missing then the license can be retrieved from +# https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +# +# This is an example script that manages locally generated self-signed +# certificates on behalf of the 5GMS Application Function. +# + +# Save location of this script and the name it was called by +scriptname=`basename "$0"` +scriptdir=`dirname "$0"` +scriptdir=`cd "$scriptdir"; pwd` + +# Constants +default_cert_op= +cert_store="@prefix@/@localstatedir@/cache/rt-5gms/af/certificates" + +# Variables +cert_operation= +common_name= +server_certificate_resource_id= +cert_status= +cert_subject= +cache_control_max_age=70 + +print_syntax() { + echo "Syntax: $scriptname -h" + echo " $scriptname -c [...]" +} + +# Parse command line arguments +ARGS=`getopt -n "$scriptname" -o 'c:h' -l 'cert-operation:,help' -s sh -- "$@"` + +if [ $? -ne 0 ]; then + print_syntax >&2 + exit 1 +fi + +debug() { + #echo "$@" >&2 + true; +} + +error() { + echo "$@" >&2 +} + +print_help() { + cat < + + certificate-id The certificate ID to create a new key and certificate + signing request. + +newcert parameters: + syntax: newcert + + certificate-id The certificate ID to create a new key and public + certificate. + +publiccert parameters: + syntax: publiccert + + certificate-id The certificate ID to fetch the public certificate for. + +servercert parameters: + syntax: servercert + + certificate-id The certificate ID to fetch the private key and + certificate for. + +setcert parameters: + syntax: setcert < + + certificate-id The certificate ID for which the public certificate is + being uploaded. + +revoke parameters: + syntax: revoke + + certificate-id The certificate ID to revoke. + +delete parameters: + syntax: delete + + certificate-id The certificate ID to delete. + +list parameters: + syntax: list [...] +EOF +} + +eval set -- "$ARGS" +unset ARGS + +CERTOPS="$default_cert_op" + +while true; do + case "$1" in + -c|--cert-operation) + CERTOPS="$2" + shift 2 + continue + ;; + -h|--help) + print_help + exit 0 + ;; + --) + shift + break + ;; + *) + echo "Error: Command line argument \"$1\" unexpected" >&2 + print_syntax >&2 + exit 1 + ;; + esac +done + +if [ -z "$CERTOPS" ]; then + error 'Error: Required command line parameter are missing' + print_syntax >&2 + exit 1 +fi + +error_exit() { + exit_code="$1" + shift + error "$@" + exit "$exit_code" +} + +cert_store_create() { + if [ ! -d "$cert_store/csrs" ]; then + mkdir -p "$cert_store/csrs" + fi + + if [ ! -d "$cert_store/private" ]; then + mkdir -p "$cert_store/private" + fi + + if [ ! -d "$cert_store/public" ]; then + mkdir -p "$cert_store/public" + fi +} + +cert_store_check() { + cert_id="$1" + if [ -f "$cert_store/csrs/$cert_id.pem" ]; then + error_exit 3 "CSR for Server Certificate Resource $cert_id exists already" + fi + + if [ -f "$cert_store/public/$cert_id.pem" ]; then + error_exit 3 "Certificate for Server Certificate Resource $cert_id exists already" + fi +} + +new_csr() { + cert_id="$1" + common_name="$2" + cert_store_check "$cert_id" + + openssl req -new -newkey rsa:2048 -batch -nodes -keyout "$cert_store/private/$cert_id.pem" -out "$cert_store/csrs/$cert_id.pem" -subj "/C=GB/L=London/CN=$common_name" -addext "subjectAltName=DNS:$common_name" > /dev/null 2>&1 + + ts=`stat -c '%Y' "$cert_store/csrs/$cert_id.pem"` + timestamp=`TZ=GMT date --date=@$ts +'%a, %d %b %Y %H:%M:%S %Z'` + hashsum=$(sha256sum "$cert_store/csrs/$cert_id.pem"|sed 's/ .*//') + + echo "Last-Modified: $timestamp" + echo "ETag: $hashsum" + echo "Cache-Control: max-age=$cache_control_max_age" + cat "$cert_store/csrs/$cert_id.pem" + + exit 0 + +} + +new_cert() { + cert_id="$1" + common_name="$2" + + cert_store_check "$cert_id" + + # Generate server cert to be signed + openssl req -new -nodes -x509 -days 90 -newkey rsa:2048 -keyout "$cert_store/private/$cert_id.pem" -out "$cert_store/public/$cert_id.pem" -subj "/C=GB/L=London/CN=$common_name" -addext "subjectAltName=DNS:$common_name"> /dev/null 2>&1 + + ts=`stat -c '%Y' "$cert_store/public/$cert_id.pem"` + timestamp=`TZ=GMT date --date=@"$ts" +'%a, %d %b %Y %H:%M:%S %Z'` + hashsum=$(sha256sum "$cert_store/public/$cert_id.pem" | sed 's/ .*//') + + echo "Last-Modified: $timestamp" + echo "ETag: $hashsum" + echo "Cache-Control: max-age=$cache_control_max_age" + cat "$cert_store/public/$cert_id.pem" + + exit 0 +} + +public_cert_get() { + cert_id="$1" + if ([ -f "$cert_store/csrs/$cert_id.pem" ] && ! [ -f "$cert_store/public/$cert_id.pem" ]); then + error_exit 8 "Public Certificate for $cert_id not yet available." + fi + + if [ ! -f "$cert_store/public/$cert_id.pem" ]; then + error_exit 4 "Certificate for $cert_id not found" + fi + + ts=`stat -c '%Y' "$cert_store/public/$cert_id.pem"` + timestamp=`TZ=GMT date --date=@$ts +'%a, %d %b %Y %H:%M:%S %Z'` + hashsum=$(sha256sum "$cert_store/public/$cert_id.pem"|sed 's/ .*//') + + echo "Last-Modified: $timestamp" + echo "ETag: $hashsum" + echo "Cache-Control: max-age=$cache_control_max_age" + cat "$cert_store/public/$cert_id.pem" + + exit 0 +} + +server_cert_get() { + cert_id="$1" + if [[ ! -f "$cert_store/public/$cert_id.pem" || ! -f "$cert_store/private/$cert_id.pem" ]]; then + error_exit 8 "Credentials for $cert_id not yet available." + fi + + ts=$(stat -c '%Y' "$cert_store/public/$cert_id.pem") + timestamp=$(TZ=GMT date --date=@$ts +'%a, %d %b %Y %H:%M:%S %Z') + hashsum=$(sha256sum "$cert_store/public/$cert_id.pem"|sed 's/ .*//') + + echo "Last-Modified: $timestamp" + echo "ETag: $hashsum" + echo "Cache-Control: max-age=$cache_control_max_age" + cat "$cert_store/public/$cert_id.pem" + echo "" + cat "$cert_store/private/$cert_id.pem" + + exit 0 +} + +cert_set() { + cert_id="$1" + if [[ ! -f "$cert_store/csrs/$cert_id.pem" ]]; then + error_exit 4 "No CSR issued: $cert_id." + fi + + if [[ -f "$cert_store/public/$cert_id.pem" ]]; then + error_exit 3 "Certificate already exists for $cert_id." + fi + + cat > "$cert_store/public/$cert_id.pem" + exit 0 +} + +cert_expiry_check() { + cert_id="$1" + if openssl x509 -checkend 86400 -noout -in "$cert_store/public/$cert_id.pem" >/dev/null 2>&1; then + cert_status= + else + cert_status="Expired or will expire within 24 hours" + fi +} + +cert_list_entry() { + cert_id="$1" + if [[ -f "$cert_store/private/$cert_id.pem" && ! -f "$cert_store/public/$cert_id.pem" ]]; then + cert_status="Awaiting" + cert_subject= + elif [[ -f "$cert_store/public/$cert_id.pem" ]]; then + cert_expiry_check "$cert_id" >&2 + cert_subject=$(openssl x509 -noout -subject -in "$cert_store/public/$cert_id.pem") + fi + echo -e "${cert_id}\t${cert_subject}\t${cert_status}" +} + +cert_list() { + if [[ $# -eq 0 ]]; then + eval set -- $(cd "$cert_store/private"; ls *.pem 2>/dev/null | sed 's/\.pem$//') + fi + for cert in "$@"; do + cert_list_entry "$cert" + done +} + +check_cert_revoke() { + cert_id="$1" + if [[ -f "$cert_store/csr/$cert_id.pem" ]]; then + can_be_revoked=0 + error "Cannot revoke as $cert_id.pem is an externally signed certificate" + else + can_be_revoked=0 + error "Cannot revoke as $cert_id.pem is a self-signed certificate" + fi + #issuer=$(openssl x509 -in "$cert_store/public/$cert_id.pem" -inform PEM -noout -issuer | sed 's/issuer=//') + #subject=$(openssl x509 -in "$cert_store/public/$cert_id.pem" -inform PEM -noout -subject | sed 's/subject=//') + #if [ "$issuer" = "$subject" ]; then + # can_be_revoked=0 + # error "Cannot revoke as $cert_id.pem is a self-signed certificate" + #else + # can_be_revoked=1 + #fi +} + +cert_revoke() { + cert_id="$1" + check_cert_revoke "$cert_id" + debug "in cert_revoke: $can_be_revoked" + if [ "$can_be_revoked" -eq "0" ] ; then + + debug "in cert_revoke:exit 2 $can_be_revoked" + exit 2 + fi + + #openssl ca -revoke "$cert_store/public/$cert_id.pem" -keyfile "$cert_store/private/ca.key" -cert "$cert_store/public/ca.crt" + exit 0 +} + +cert_delete() { + cert_id="$1" + rm -f "$cert_store/private/$cert_id.pem" + rm -f "$cert_store/public/$cert_id.pem" + rm -f "$cert_store/csrs/$cert_id.pem" +} + +certificate_delete() { + cert_id="$1" + check_cert_revoke "$cert_id" + if [ "$can_be_revoked" -ne 0 ] ; then + cert_revoke "$cert_id" + fi + cert_delete "$cert_id" + exit 0 +} + +parse_opts() { + if [ "$CERTOPS" == "newcsr" ]; then + if [ $# -ne 2 ]; then + echo "$CERTOPS: Wrong parameters to create a new csr" + exit 1 + fi + new_csr "$@" + exit 1 + fi + + if [ "$CERTOPS" == "newcert" ]; then + if [ $# -ne 2 ]; then + echo "$CERTOPS: Wrong parameters to create a new certificate" + exit 1 + fi + new_cert "$@" + exit 1 + fi + + if [ "$CERTOPS" == "publiccert" ]; then + if [[ $# -ne 1 ]]; then + error_exit 1 "$CERTOPS: has invalid options" + fi + public_cert_get "$@" + exit 1 + fi + + if [ "$CERTOPS" == "servercert" ]; then + if [ $# -ne 1 ]; then + error_exit 1 "$CERTOPS: has invalid options" + fi + server_cert_get "$@" + exit 1 + fi + + if [ "$CERTOPS" == "setcert" ]; then + if [ $# -ne 1 ]; then + error_exit 1 "$CERTOPS: has invalid options" + fi + cert_set "$@" + exit 1 + fi + + if [ "$CERTOPS" == "revoke" ]; then + if [ $# -ne 1 ]; then + error_exit 1 "$CERTOPS: has invalid options" + fi + cert_revoke "$@" + exit 1 + fi + + if [ "$CERTOPS" == "delete" ]; then + if [ $# -ne 1 ]; then + error_exit 1 "$CERTOPS: has invalid options" + fi + certificate_delete "$@" + exit 1 + fi + + if [ "$CERTOPS" == "list" ]; then + cert_list "$@" + fi +} + +cert_store_create +parse_opts "$@" + +exit 0 diff --git a/tools/meson.build b/tools/meson.build new file mode 100644 index 0000000..459abd9 --- /dev/null +++ b/tools/meson.build @@ -0,0 +1,44 @@ +pymod = import('python') +fs = import('fs') + +support_scripts_dir = get_option('libexecdir') / 'rt-5gms' + +scripts = { +'python3/m1_client_cli.py': 'm1-client' +} + +support_scripts = { +'bash/certmgr': 'self-signed-certmgr' +} + +self_signed_certmgr_runtime = support_scripts_dir / 'self-signed-certmgr' + +python3_modules = [ + 'python3/lib/rt_m1_client', +] + +scripts_conf_data = configuration_data() +script_conf_options = [ + 'prefix', 'bindir', 'libdir', 'libexecdir', 'localstatedir', 'sbindir', + 'sysconfdir', + ] +foreach opt : script_conf_options + scripts_conf_data.set(opt, get_option(opt)) +endforeach + +foreach src, dst : scripts + scriptfile = configure_file(input: src, configuration: scripts_conf_data, output: dst) + install_data(scriptfile, install_dir: get_option('bindir'), install_mode: 'rwxr-xr-x') +endforeach + +foreach src, dst : support_scripts + scriptfile = configure_file(input: src, configuration: scripts_conf_data, output: dst) + install_data(scriptfile, install_dir: support_scripts_dir, install_mode: 'rwxr-xr-x') +endforeach + +python3 = pymod.find_installation('python3') +sh = find_program('sh') +foreach pm : python3_modules + mod_files = files(run_command(sh, '-c', 'cd "$MESON_SOURCE_ROOT/$MESON_SUBDIR"; find "' + pm + '" -type f -name "*.py" -print').stdout().strip().split('\n')) + python3.install_sources(mod_files, subdir: fs.name(pm)) +endforeach diff --git a/tools/python3/lib/rt_m1_client/client.py b/tools/python3/lib/rt_m1_client/client.py new file mode 100644 index 0000000..b9f0090 --- /dev/null +++ b/tools/python3/lib/rt_m1_client/client.py @@ -0,0 +1,622 @@ +#!/usr/bin/python3 +#============================================================================== +# 5G-MAG Reference Tools: M1 Client +#============================================================================== +# +# File: m1_client/client.py +# License: 5G-MAG Public License (v1.0) +# Author: David Waring +# Copyright: (C) 2022 British Broadcasting Corporation +# +# For full license terms please see the LICENSE file distributed with this +# program. If this file is missing then the license can be retrieved from +# https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +# +#============================================================================== +# +# M1 Client class +# =============== +# +# This module contains an M1 Client written as a Python 3 class using asyncio. +# +'''5G-MAG Reference Tools: M1 Client class +======================================= + +This class provides a simple interface for maintaining a connection to an M1 +server, converting Python types to the various M1 requests, parsing the +responses and conversion back to Python types or Exceptions when errors have +occurred. This class will ensure that the out going request headers are +formatted according to 3GPP TS 26.512. Message bodies are passed through as +is and therefore it is the responsibility of the application using this class +to format the body correctly. + +This class is not intended to maintain client state for an M1 session, that +should be performed outside of this class. +''' +import datetime +import json +import logging +from typing import Optional, Union, Tuple, Dict, Any, TypedDict + +import httpx + +from .exceptions import (M1ClientError, M1ServerError) +from .types import (ApplicationId, ContentHostingConfiguration, ContentProtocols, + ProvisioningSessionType, ProvisioningSession, ResourceId) + +class TagAndDateResponse(TypedDict, total=False): + '''Response containing ETag and Last-Modified headers + ''' + ETag: str + LastModified: datetime.datetime + +class ProvisioningSessionResponse(TagAndDateResponse, total=False): + '''Response containing a provisioning session object + ''' + ProvisioningSessionId: ResourceId + ProvisioningSession: ProvisioningSession + +class ContentHostingConfigurationResponse(TagAndDateResponse, total=False): + '''Response containing a content hosting configuration + ''' + ProvisioningSessionId: ResourceId + ContentHostingConfiguration: ContentHostingConfiguration + +class ServerCertificateResponse(TagAndDateResponse, total=False): + '''Response containing a server certificate + ''' + ProvisioningSessionId: ResourceId + ServerCertificateId: ResourceId + ServerCertificate: str + +class ServerCertificateSigningRequestResponse(TagAndDateResponse, total=False): + '''Response containing a CSR for a reserved certificate + ''' + ProvisioningSessionId: ResourceId + ServerCertificateId: ResourceId + CertificateSigningRequestPEM: str + +class ContentProtocolsResponse(TagAndDateResponse, total=False): + ProvisioningSessionId: ResourceId + ContentProtocols: ContentProtocols + +class M1Client: + '''5G-MAG Reference Tools: M1 Client + ''' + + def __init__(self, host_address: Tuple[str,int]): + ''' + Constructor + + host_address (tuple(str,int)) - 5GMS Application Function to connect to as a tuple of + hostname/ip-addr and TCP port number. + ''' + self.__host_address = host_address + self.__connection = None + self.__log = logging.getLogger(__name__) + + # TS26512_M1_ProvisioningSession + + async def createProvisioningSession(self, provisioning_session_type: ProvisioningSessionType, + external_application_id: ApplicationId, + asp_id: Optional[ApplicationId] = None + ) -> Optional[ProvisioningSessionResponse]: + ''' + Create a provisioning session on the 5GMS Application Function + + Parameters: + provisioning_session_type (ProvisioningSessionType) + The provisioning session type to create. + external_application_id (str) + The application ID of the external application requesting the new provisioning + session. + asp_id (optional str) + The Application Server Provider ID. + + Returns the ResourceId of the allocated provisioning session or None if there was an error. + + Throws M1ClientError if there was a problem with the request and M1ServerError if there was + a server side issue preventing the creation of the provisioning session. + ''' + self.__debug('M1Client.createProvisioningSession(%r, %r, asp_id=%r)', + provisioning_session_type, external_application_id, asp_id) + send: ProvisioningSession = { + 'provisioningSessionType': provisioning_session_type, + 'externalApplicationId': external_application_id + } + if asp_id is not None: + send['aspId'] = asp_id + result = await self.__do_request('POST', '/provisioning-sessions', json.dumps(send), + 'application/json') + if result['status_code'] == 201: + ret: ProvisioningSessionResponse = {'ProvisioningSessionId': result['headers']['location'].split('/')[-1]} + if len(result['body']) > 0: + ret.update(self.__tag_and_date(result)) + ret['ProvisioningSession'] = ProvisioningSession.fromJSON(result['body']) + return ret + self.__default_response(result) + return None + + async def getProvisioningSessionById(self, + provisioning_session_id: ResourceId + ) -> Optional[ProvisioningSessionResponse]: + ''' + Get a provisioning session from the 5GMS Application Function + + provisioning_session_id (ResourceId) + The provisioning session to find. + + Returns a ProvisioningSession structure if the provisioning session was found, or None if + the provisioning session was not found. + + Throws M1ClientError if there was a problem with the request and M1ServerError if there was + a server side issue preventing the creation of the provisioning session. + ''' + result = await self.__do_request('GET', + '/provisioning-sessions/' + provisioning_session_id, '', + 'application/json') + if result['status_code'] == 200: + ret: ProvisioningSessionResponse = self.__tag_and_date(result) + ret.update({ + 'ProvisioningSessionId': provisioning_session_id, + 'ProvisioningSession': ProvisioningSession.fromJSON(result['body']) + }) + return ret + if result['status_code'] == 404: + return None + self.__default_response(result) + return None + + async def destroyProvisioningSession(self, provisioning_session_id: ResourceId) -> bool: + ''' + Destroy a provisioning session on the 5GMS Application Function + + provisioning_session_id (ResourceId) + The provisioning session to find. + + Returns True if a provisioning session was deleted or False if there was no action. + + Throws M1ClientError if there was a problem with the request and M1ServerError if there was + a server side issue preventing the creation of the provisioning session. + ''' + result = await self.__do_request('DELETE', + '/provisioning-sessions/' + provisioning_session_id, '', + 'application/json') + if result['status_code'] == 204: + return True + self.__default_response(result) + return False + + # TS26512_M1_ContentHostingProvisioning + + async def createContentHostingConfiguration(self, provisioning_session_id: ResourceId, + content_hosting_configuration: ContentHostingConfiguration + ) -> Union[bool,ContentHostingConfigurationResponse]: + ''' + Create a content hosting configuration for a provisioning session + + provisioning_session_id (ResourceId) + The provisioning session to create the content hosting configuration in. + content_hosting_configuration (ContentHostingConfiguration) + The content hosting configuration template to use. + ''' + result = await self.__do_request('POST', + f'/provisioning-sessions/{provisioning_session_id}/content-hosting-configuration', + json.dumps(content_hosting_configuration), 'application/json') + if result['status_code'] == 201: + if len(result['body']) > 0: + ret: ContentHostingConfigurationResponse = self.__tag_and_date(result) + ret.update({ + 'ProvisioningSessionId': provisioning_session_id, + }) + if len(result['body']) > 0: + ret.update({ + 'ContentHostingConfiguration': ContentHostingConfiguration.fromJSON( + result['body']) + }) + return ret + return True + self.__default_response(result) + return False + + async def retrieveContentHostingConfiguration(self, provisioning_session_id: ResourceId + ) -> Optional[ContentHostingConfigurationResponse]: + ''' + Fetch the content hosting configuration for a provisioning session + + provisioning_session_id (ResourceId) + The provisioning session to fetch the current content hosting configuration for. + + Returns None if the provisioning session does not exist, also returns None if the + provisioning session exists but does not have a content hosting configuration, + otherwise returns the content hosting configuration and metadata. + ''' + result = await self.__do_request('GET', + f'/provisioning-sessions/{provisioning_session_id}/content-hosting-configuration', + '', 'application/json') + if result['status_code'] == 200: + ret: ContentHostingConfigurationResponse = self.__tag_and_date(result) + ret.update({ + 'ProvisioningSessionId': provisioning_session_id, + 'ContentHostingConfiguration': ContentHostingConfiguration.fromJSON(result['body']) + }) + return ret + if result['status_code'] == 404: + return None + self.__default_response(result) + return None + + async def updateContentHostingConfiguration(self, provisioning_session_id: ResourceId, + content_hosting_configuration: ContentHostingConfiguration + ) -> Union[bool,ContentHostingConfigurationResponse]: + ''' + Update a content hosting configuration for a provisioning session + + provisioning_session_id (ResourceId) + The provisioning session to update the current content hosting configuration for. + content_hosting_configuration (ContentHostingConfiguration) + The new content hosting configuration to apply. + + Returns the content hosting configuration and metadata if the update succeeded and the new + content hosting configuration was returned, or True if the update succeeded but no + content hosting configuration was returned, or False if the update failed. + ''' + result = await self.__do_request('PUT', + f'/provisioning-sessions/{provisioning_session_id}/content-hosting-configuration', + + str(content_hosting_configuration), 'application/json') + if result['status_code'] == 204: + if len(result['body']) > 0: + ret: ContentHostingConfigurationResponse = self.__tag_and_date(result) + ret.update({ + 'ProvisioningSessionId': provisioning_session_id, + 'ContentHostingConfiguration': ContentHostingConfiguration.fromJSON( + result['body']) + }) + return ret + return True + if result['status_code'] == 404: + return False + self.__default_response(result) + return False + + async def patchContentHostingConfiguration(self, provisioning_session_id: ResourceId, patch: str + ) -> Union[bool,ContentHostingConfigurationResponse]: + ''' + Patch a content hosting configuration for a provisioning session using a JSON patch + + provisioning_session_id (ResourceId) + The provisioning session to update the current content hosting configuration for. + patch (str) + The patch information in JSON patch format. + + Returns the content hosting configuration and metadata if the patch succeeded and the new + content hosting configuration was returned, or True if the patch succeeded but no + content hosting configuration was returned, or False if the patch failed. + ''' + result = await self.__do_request('PATCH', + f'/provisioning-sessions/{provisioning_session_id}/content-hosting-configuration', + + patch, 'application/json-patch+json') + if result['status_code'] == 200: + if len(result['body']) > 0: + ret: ContentHostingConfigurationResponse = self.__tag_and_date(result) + ret.update({ + 'ProvisioningSessionId': provisioning_session_id, + 'ContentHostingConfiguration': ContentHostingConfiguration.fromJSON( + result['body']) + }) + return ret + return True + if result['status_code'] == 404: + return False + self.__default_response(result) + return False + + async def destroyContentHostingConfiguration(self, provisioning_session_id: ResourceId + ) -> bool: + ''' + Delete a content hosting configuration for a provisioning session + + provisioning_session_id (ResourceId) + The provisioning session to remove the content hosting configuration for. + + Return True if the content hosting configuration was deleted or False if the content hosting + configuration did not exist. + ''' + result = await self.__do_request('DELETE', + f'/provisioning-sessions/{provisioning_session_id}/content-hosting-configuration', + '', 'application/json') + if result['status_code'] == 204: + return True + if result['status_code'] == 404: + return False + self.__default_response(result) + return False + + async def purgeContentHostingCache(self, provisioning_session_id: ResourceId, + filter_regex: Optional[str] = None) -> Optional[int]: + ''' + Purge cache entries for a provisioning session + + provisioning_session_id (ResourceId) + The provisioning session to purge cache entries for. + filter_regex (str) + Optional regular expression to match the cache entries origin URL path. + + Return the number of purged entries, or None if no purge took place. + ''' + body = '' + if filter_regex is not None: + body = f'pattern={filter_regex}' + result = await self.__do_request('POST', + f'/provisioning-sessions/{provisioning_session_id}/content-hosting-configuration/purge', + body, 'application/x-www-form-urlencoded') + if result['status_code'] == 200: + return int(result['body']) + if result['status_code'] == 204: + return None + self.__default_response(result) + return None + + # TS26512_M1_ServerCertificatesProvisioning + + async def createOrReserveServerCertificate(self, provisioning_session_id: ResourceId, csr=False) -> Optional[ServerCertificateSigningRequestResponse]: + '''Create or reserve a server certificate for a provisioing session + + provisioning_session_id (ResourceId) + The provisioning session to create the new certificate entry in. + csr (bool) + Whether to reserve a certificate and return the CSR PEM data. + + If csr is True then this will reserve the certificate and request the + CSR PEM data be returned along side the Id of the newly reserved + certificate. + + If csr is False or not provided then create a new certificate and just + return the new certificate Id. + + Return a tuple containing the new certificate Id and an optional CSR + PEM data string. + ''' + + url = f'/provisioning-sessions/{provisioning_session_id}/certificates' + if csr: + url += '?csr=true' + result = await self.__do_request('POST', url, '', 'application/octet-stream') + if result['status_code'] == 200: + certificate_id = result['headers'].get('Location','').rsplit('/',1)[1] + ret: ServerCertificateSigningRequestResponse = self.__tag_and_date(result) + ret.update({ + 'ProvisioningSessionId': provisioning_session_id, + 'ServerCertificateId': certificate_id, + }) + if csr and len(result['body']) > 0: + ret.update({ + 'CertificateSigningRequestPEM': result['body'], + }) + return ret + self.__default_response(result) + return None + + async def createServerCertificate(self, provisioning_session_id: ResourceId) -> ServerCertificateResponse: + '''Create a new certificate for a provisioning session + + provisioning_session_id (ResourceId) + The provisioning session to create the new certificate entry in. + + Returns the certificate Id of the newly created certificate. + ''' + result = await self.createOrReserveServerCertificate(provisioning_session_id, csr=False) + return result + + async def reserveServerCertificate(self, provisioning_session_id: ResourceId) -> ServerCertificateSigningRequestResponse: + '''Reserve a certificate for a provisioning session and get the CSR PEM + + provisioning_session_id (ResourceId) + The provisioning session to create the new certificate entry in. + + Returns a CSR as a PEM string plus metadata for the reserved certificate. + ''' + result = await self.createOrReserveServerCertificate(provisioning_session_id, csr=True) + if result is None or 'CertificateSigningRequestPEM' not in result: + raise M1ClientError(reason = f'Failed to retrieve CSR for session {provisioning_session_id}', status_code = 200) + return result + + async def uploadServerCertificate(self, provisioning_session_id: ResourceId, certificate_id: ResourceId, pem_data: str) -> bool: + '''Upload the signed public certificate for a reserved certificate + + provisioning_session_id (ResourceId) + The provisioning session the certificate was reserved for. + certificate_id (ResourceId) + The certificate Id of the reserved certificate. + pem_data (str) + A string containing the PEM data for the public certificate to + upload. + + Returns True if successful or False if the certificate has already been + uploaded. + ''' + result = await self.__do_request('PUT', + f'/provisioning-sessions/{provisioning_session_id}/certificates/{certificate_id}', + pem_data, 'application/x-pem-file') + if result['status_code'] == 204: + return True + self.__default_response(result) + return False + + async def retrieveServerCertificate(self, provisioning_session_id: ResourceId, certificate_id: ResourceId) -> Optional[ServerCertificateResponse]: + '''Retrieve the public certificate for a given certificate Id + + provisioning_session_id (ResourceId) + The provisioning session for the certificate. + certificate_id (ResourceId) + The certificate Id of the certificate. + + Returns the PEM data for the public certificate and its metadata or + None if the certificate is reserved and awaiting upload. + + Raises M1ClientError with status_code 404 if the certificate is not found. + ''' + result = await self.__do_request('GET', + f'/provisioning-sessions/{provisioning_session_id}/certificates/{certificate_id}', + '', 'application/octet-stream') + if result['status_code'] == 200: + ret: ServerCertificateResponse = self.__tag_and_date(result) + ret['ProvisioningSessionId'] = provisioning_session_id + ret['ServerCertificateId'] = certificate_id + ret['ServerCertificate'] = result['body'] + return ret + if result['status_code'] == 204: + return None + if result['status_code'] == 404: + raise M1ClientError(reason="Certificate not found", status_code=404) + self.__default_response(result) + return None + + async def destroyServerCertificate(self, provisioning_session_id: ResourceId, certificate_id: ResourceId) -> bool: + '''Delete a certificate. + + provisioning_session_id (ResourceId) + The provisioning session for the certificate. + certificate_id (ResourceId) + The certificate Id of the certificate. + + Returns True if the certificate has been deleted. + ''' + result = await self.__do_request('DELETE', + f'/provisioning-sessions/{provisioning_session_id}/certificates/{certificate_id}', + '', 'application/octet-stream') + if result['status_code'] == 204: + return True + self.__default_response(result) + return False + + # TS26512_M1_ContentProtocolsDiscovery + async def retrieveContentProtocols(self, provisioning_session_id: ResourceId) -> Optional[ContentProtocolsResponse]: + '''Get the ContentProtocols information for the provisioning session + + provisioning_session_id (ResourceId) + The provisioning session to get the ContentProtocols for. + + Returns a ContentProtocols structure and metadata. + ''' + result = await self.__do_request('GET', + f'/provisioning-sessions/{provisioning_session_id}/protocols', + '', 'application/octet-stream') + if result['status_code'] == 200: + ret: ContentProtocolsResponse = self.__tag_and_date(result) + ret['ContentProtocols'] = ContentProtocols.fromJSON(result['body']) + return ret + self.__default_response(result) + return None + + # TS26512_M1_ConsumptionReportingProvisioning + #async def activateConsumptionReporting(self, provisioning_session_id: ResourceId, consumption_reporting_config: ConsumptionReportingConfiguration) -> Optional[ResourceId]: + #async def retrieveConsumptionReportingConfiguration(self, provisioning_session_id: ResourceId, consumption_reporting_id: ResourceId) -> ConsumptionReportingConfigurationResponse: + #async def updateConsumptionReportingConfiguration(self, provisioning_session_id: ResourceId, consumption_reporting_config: ConsumptionReportingConfiguration) -> bool: + #async def patchConsumptionReportingConfiguration(self, provisioning_session_id: ResourceId, patch: str) -> ConsumptionReportingConfigurationResponse: + #async def destroyConsumptionReportingConfiguration(self, provisioning_session_id: ResourceId, consumption_reporting_id: ResourceId) -> bool: + + # TS26512_M1_ContentPreparationTemplatesProvisioning + #async def createContentPreparationTemplate(self, provisioning_session_id: ResourceId, content_preparation_template: Any) -> Optional[ResourceId]: + #async def retrieveContentPreparationTemplate(self, provisioning_session_id: ResourceId, content_preparation_template_id: ResourceId) -> ContentPreparationTemplateResponse: + #async def updateContentPreparationTemplate(self, provisioning_session_id: ResourceId, content_preparation_template_id: ResourceId, content_preparation_template: Any) -> bool: + #async def patchContentPreparationTemplate(self, provisioning_session_id: ResourceId, content_preparation_template_id: ResourceId, patch: str) -> ContentPreparationTemplateResponse: + #async def destroyContentPreparationTemplate(self, provisioning_session_id: ResourceId, content_preparation_template_id: ResourceId) -> bool: + + # TS26512_M1_EdgeResourcesProvisioning + #async def createEdgeResourcesConfiguration(self, provisioning_session_id: ResourceId, edge_resource_config: EdgeResourceConfiguration) -> Optional[ResourceId]: + #async def retrieveEdgeResourcesConfiguration(self, provisioning_session_id: ResourceId, edge_resource_config_id: ResourceId) -> EdgeResourceConfigurationResponse: + #async def updateEdgeResourcesConfiguration(self, provisioning_session_id: ResourceId, edge_resource_config_id: ResourceId, edge_resource_config: EdgeResourceConfiguration) -> bool: + #async def patchEdgeResourcesConfiguration(self, provisioning_session_id: ResourceId, edge_resource_config_id: ResourceId, patch: str) -> EdgeResourceConfigurationResponse: + #async def destroyEdgeResourcesConfiguration(self, provisioning_session_id: ResourceId, edge_resource_config_id: ResourceId) -> bool: + + # TS26512_M1_EventDataProcessingProvisioning + #async def createEventDataProcessingConfiguration(self, provisioning_session_id: ResourceId, event_data_processing_config: EventDataProcessingConfiguration) -> Optional[ResourceId]: + #async def retrieveEventDataProcessingConfiguration(self, provisioning_session_id: ResourceId, event_data_processing_config_id: ResourceId) -> EventDataProcessingConfigurationResponse: + #async def updateEventDataProcessingConfiguration(self, provisioning_session_id: ResourceId, event_data_processing_config_id: ResourceId, event_data_processing_config: EventDataProcessingConfiguration) -> bool: + #async def patchEventDataProcessingConfiguration(self, provisioning_session_id: ResourceId, event_data_processing_config_id: ResourceId, patch: str) -> EventDataProcessingConfigurationResponse: + #async def destroyEventDataProcessingConfiguration(self, provisioning_session_id: ResourceId, event_data_processing_config_id: ResourceId) -> bool: + + # TS26512_M1_MetricsReportingProvisioning + #async def activateMetricsReporting(self, provisioning_session_id: ResourceId, metrics_reporting_config: MetricsReportingConfiguration) -> ResourceId: + #async def retrieveMetricsReportingConfiguration(self, provisioning_session_id: ResourceId, metrics_reporting_config_id: ResourceId) -> MetricsReportingConfigurationResponse: + #async def updateMetricsReportingConfiguration(self, provisioning_session_id: ResourceId, metrics_reporting_config_id: ResourceId, metrics_reporting_config: MetricsReportingConfiguration) -> bool: + #async def patchMetricsReportingConfiguration(self, provisioning_session_id: ResourceId, metrics_reporting_config_id: ResourceId, patch: str) -> MetricsReportingConfigurationResponse: + #sync def destroyMetricsReportingConfiguration(self, provisioning_session_id: ResourceId, metrics_reporting_config_id: ResourceId) -> bool: + + # TS26512_M1_PolicyTemplatesProvisioning + #async def createPolicyTemplate(self, provisioning_session_id: ResourceId, policy_template: PolicyTemplate) -> Optional[ResourceId]: + #async def retrievePolicyTemplate(self, provisioning_session_id: ResourceId, policy_template_id: ResourceId) -> PolicyTemplateResponse: + #async def updatePolicyTemplate(self, provisioning_session_id: ResourceId, policy_template_id: ResourceId, policy_template: PolicyTemplate) -> bool: + #async def patchPolicyTemplate(self, provisioning_session_id: ResourceId, policy_template_id: ResourceId, patch: str) -> PolicyTemplateResponse: + #async def destroyPolicyTemplate(self, provisioning_session_id: ResourceId, policy_template_id: ResourceId) -> bool: + + # Private methods + + async def __do_request(self, method: str, url_suffix: str, body: Union[str,bytes], + content_type: str, headers: Optional[dict] = None) -> Dict[str,Any]: + '''Send a request to the 5GMS Application Function + ''' + # pylint: disable=too-many-arguments + if isinstance(body, str): + body = bytes(body, 'utf-8') + req_headers = {'Content-Type': content_type} + if headers is not None: + req_headers.update(headers) + url = f'http://{self.__host_address[0]}:{self.__host_address[1]}/3gpp-m1/v2{url_suffix}' + if self.__connection is None: + self.__connection = httpx.AsyncClient(http1=True, http2=False, + headers={'User-Agent': '5GMS-AF/testing'}) + req = self.__connection.build_request(method, url, headers=req_headers, data=body) + try: + resp = await self.__connection.send(req) + except httpx.RemoteProtocolError as err: + raise M1ServerError(reason=f'Communication with the Application Function failed: {err}', status_code=500) + return {'status_code': resp.status_code, 'body': resp.text, 'headers': resp.headers} + + def __default_response(self, result: Dict[str,Any]) -> None: + '''Handle default actions for all responses from the 5GMS Application Function + ''' + if result['status_code'] >= 400 and result['status_code'] < 500: + raise M1ClientError(reason='M1 operation failed: '+str(result['body']), + status_code=result['status_code']) + if result['status_code'] >= 500 and result['status_code'] < 600: + raise M1ServerError(reason='M1 operation failed: '+str(result['body']), + status_code=result['status_code']) + + @staticmethod + def __tag_and_date(result: Dict[str,Any]) -> TagAndDateResponse: + ret = {'ETag': result['headers'].get('etag')} + lm_dt = result['headers'].get('last-modified') + if lm_dt is not None: + try: + lm_dt = datetime.datetime.strptime(lm_dt, '%a, %d %b %Y %H:%M:%S %Z').replace( + tzinfo=datetime.timezone.utc) + except ValueError: + try: + lm_dt = datetime.datetime.strptime(lm_dt, '%A, %d-%b-%y %H:%M:%S %Z').replace( + tzinfo=datetime.timezone.utc) + except ValueError: + try: + lm_dt = datetime.datetime.strptime(lm_dt, '%a %b %d %H:%M:%S %Y').replace( + tzinfo=datetime.timezone.utc) + except ValueError: + lm_dt = None + ret['Last-Modified'] = lm_dt + return ret + + def __debug(self, *args, **kwargs): + self.__log.debug(*args, **kwargs) + +__all__ = [ + # Types + 'ProvisioningSessionResponse', + 'ContentHostingConfigurationResponse', + 'ServerCertificateResponse', + 'ServerCertificateSigningRequestResponse', + 'ContentProtocolsResponse', + # Classes + 'M1Client', + ] diff --git a/tools/python3/lib/rt_m1_client/exceptions.py b/tools/python3/lib/rt_m1_client/exceptions.py new file mode 100644 index 0000000..d8a7b13 --- /dev/null +++ b/tools/python3/lib/rt_m1_client/exceptions.py @@ -0,0 +1,113 @@ +#!/usr/bin/python3 +#============================================================================== +# 5G-MAG Reference Tools: M1 Client Exceptions +#============================================================================== +# +# File: rt_m1_client/exceptions.py +# License: 5G-MAG Public License (v1.0) +# Author: David Waring +# Copyright: (C) 2023 British Broadcasting Corporation +# +# For full license terms please see the LICENSE file distributed with this +# program. If this file is missing then the license can be retrieved from +# https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +# +#============================================================================== +# +# M1 Client Exceptions +# ==================== +# +# This module defines the exceptions used by the M1 client classes +# +# M1ClientError - Exception used for indicating client request issues as +# returned by the M1 Server (5GMS Application Function). +# +# M1ServerError - Exception used for indicating M1 server errors. The request +# that generated this error may succeed if retried at a later +# time. + +'''5G-MAG Reference Tools: M1 Client Exceptions +============================================ + +This module defines some custom exceptions used by the M1 Client class. + +The M1Error exception is the superclass of the M1ClientError and M1ServerError. +This can be used as a catch all for errors reported by the M1 Server in +response to a request. + +The M1ClientError exception derives from M1Error and is used when a request +response indicates a 4XX status code. This means that there was a problem with +the request and it should not be retried without modification to correct the +issues. + +The M1ServerError exception derives from M1Error and is used when a request +response indicates a 5XX status code. This means that there was an error on the +server. The request may be retried at a later time and may then succeed. +''' +from typing import Optional + +from .types import ProblemDetail, InvalidParam + +def format_invalid_param(inv_param: InvalidParam): + ''' + Format an InvalidParams entry for display + ''' + ret: str = inv_param['param'] + if 'reason' in inv_param and inv_param['reason'] is not None: + ret += ' : ' + inv_param['reason'] + return ret + +class M1Error(Exception): + '''Exception base class for all M1 Exceptions + + This can be used to catch both M1ClientError and M1ServerError exceptions. + ''' + def __init__(self, reason: str, # pylint: disable=useless-super-delegation + status_code: Optional[int] = None, problem_detail: Optional[ProblemDetail] = None): + super().__init__(reason, status_code, problem_detail) + + def __str__(self) -> str: + if self.args[2] is not None: + problem = self.args[2] + ret: str = '' + if self.args[1] is not None: + ret = f'[{self.args[1]}] ' + if 'title' in problem: + ret += problem['title']+'\n' + if 'description' in problem: + ret += problem['description'] + if 'invalidParams' in problem and problem['invalidParams'] is not None: + ret += '\nInvalid Parameters:\n'+'\n'.join( + [' '+format_invalid_param(p) for p in problem['invalidParams']]) + return ret + if self.args[1] is not None: + return f'[{self.args[1]}] {self.args[0]}' + return self.args[0] + + def __repr__(self) -> str: + return f'{self.__class__.__name__}(reason={self.args[0]!r}, status_code={self.args[1]!r})' + +class M1ClientError(M1Error): + '''Raised when there was a client side problem during M1 operations + + This error is raised when there was a problem with the client request + detected either by this class or by the M1 server (5GMS Application + Function) responding with a 4XX response. + + The request should not be repeated in this form as it will fail again. + ''' + +class M1ServerError(M1Error): + '''Raised when there was a server side problem during M1 operations + + This represents 5XX error responses from the M1 server (5GMS Application + Function). + + The request may be repeated. + ''' + +__all__ = [ + "M1Error", + "M1ClientError", + "M1ServerError", + ] diff --git a/tools/python3/lib/rt_m1_client/types.py b/tools/python3/lib/rt_m1_client/types.py new file mode 100644 index 0000000..e2bf332 --- /dev/null +++ b/tools/python3/lib/rt_m1_client/types.py @@ -0,0 +1,317 @@ +#!/usr/bin/python3 +#============================================================================== +# 5G-MAG Reference Tools: M1 Client types +#============================================================================== +# +# File: rt_m1_client/types.py +# License: 5G-MAG Public License (v1.0) +# Author: David Waring +# Copyright: (C) 2023 British Broadcasting Corporation +# +# For full license terms please see the LICENSE file distributed with this +# program. If this file is missing then the license can be retrieved from +# https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +# +#============================================================================== +# +# M1 Client types +# =============== +# +# Defines various types from TS 29.571 and TS 26.512 used in M1 requests + +'''5G-MAG Reference Tools: M1 Client types +======================================= + +This module defines various types from TS 29.571 and TS 26.512 used in M1 requests. + +These types can be used in static type checking in Python 3. +''' +import enum +import json +from typing import List, Literal, TypedDict + +# TS 26.512 ProvisioningSession + +ApplicationId = str +ResourceId = str +Uri = str +ProvisioningSessionId = ResourceId +ProvisioningSessionType = Literal['DOWNLINK','UPLINK'] + +class ProvisioningSessionMandatory(TypedDict): + provisioningSessionId: ProvisioningSessionId + provisioningSessionType: ProvisioningSessionType + externalApplicationId: ApplicationId + +class ProvisioningSession (ProvisioningSessionMandatory, total=False): + aspId: ApplicationId + + @staticmethod + def fromJSON(json_str: str) -> "ProvisioningSession": + ret: dict = json.loads(json_str) + for mandatory_field in ProvisioningSessionMandatory.__required_keys__: + if mandatory_field not in ret: + raise TypeError(f'ProvisioningSession must contain a {mandatory_field} field') + if ret['provisioningSessionType'] not in ProvisioningSessionType.__args__: + raise TypeError(f'ProvisioningSession.provisioningSessionType must be one of: {", ".join(ProvisioningSessionType.__args__)}') + + return ProvisioningSession(ret) + +PROVISIONING_SESSION_TYPE_DOWNLINK: ProvisioningSessionType = 'DOWNLINK' +PROVISIONING_SESSION_TYPE_UPLINK: ProvisioningSessionType = 'UPLINK' + +# TS 26.512 ContentHostingConfiguration + +class PathRewriteRule(TypedDict): + '''PathRewriteRule structure in TS 26.512 + ''' + requestPathPattern: str + mappedPath: str + +class CachingDirectivesMandatory(TypedDict): + '''Mandatory fields from CachingConfiguration.cachingDirectives structure in TS 26.512 + ''' + noCache: bool + +class CachingDirectives(CachingDirectivesMandatory, total=False): + '''CachingConfiguration.cachingDirectives structure in TS 26.512 + ''' + statusCodeFilters: List[int] + maxAge: int + +class CachingConfigurationMandatory(TypedDict): + '''Mandatory fields from CachingConfiguration structure in TS 26.512 + ''' + urlPatternFilter: str + +class CachingConfiguration(CachingConfigurationMandatory, total=False): + '''CachingConfiguration structure in TS 26.512 + ''' + cachingDirectives: CachingDirectives + +class ContentProtocolDescriptorMandatory(TypedDict): + '''Mandatory fields from ContentProtocolDescriptor in TS 26.512 + ''' + termIdentifier: Uri + +class ContentProtocolDescriptor(ContentProtocolDescriptorMandatory, total=False): + '''ContentProtocolDescriptor structure in TS 26.512 + ''' + descriptionLocator: Uri + +class ContentProtocols(TypedDict, total=False): + '''ContentProtocols structure in TS 26.512 + ''' + downlinkIngestProtocols: List[ContentProtocolDescriptor] + uplinkEgestProtocols: List[ContentProtocolDescriptor] + geoFencingLocatorTypes: List[Uri] + + @staticmethod + def fromJSON(json_str: str) -> "ContentProtocols": + return ContentProtocols(json.loads(str)) + +class DistributionNetworkType(enum.Enum): + '''Enumeration DistributionNetworkType in TS 26.512 + ''' + NETWORK_EMBMS = enum.auto() + + def __str__(self): + return self.name + +class DistributionMode(enum.Enum): + '''Enumeration DistributionMode in TS 26.512 + ''' + MODE_EXCLUSIVE = enum.auto() + MODE_HYBRID = enum.auto() + MODE_DYNAMIC = enum.auto() + + def __str__(self): + return self.name + +class DistributionConfiguration(TypedDict, total=False): + ''' + DistributionConfiguration structure in TS 26.512 + ''' + contentPreparationTemplateId: ResourceId + canonicalDomainName: str + domainNameAlias: str + baseURL: Uri + pathRewriteRules: List[PathRewriteRule] + cachingConfigurations: List[CachingConfiguration] + geoFencing: TypedDict('GeoFencing', {'locatorType': str, 'locators': List[str]}) + urlSignature: TypedDict('URLSignature', { + 'urlPattern': str, + 'tokenName': str, + 'passphraseName': str, + 'passphrase': str, + 'tokenExpiryName': str, + 'useIPAddress': bool + }) + certificateId: ResourceId + supplementaryDistributionNetworks: List[TypedDict('SupplementaryDistributionNetwork', { + 'distributionNetworkType': DistributionNetworkType, + 'distributionMode': DistributionMode, + })] + +class IngestConfiguration(TypedDict, total=False): + ''' + IngestConfiguration structure from TS 26.512 + ''' + pull: bool + protocol: Uri + baseURL: Uri + +class ContentHostingConfigurationMandatory(TypedDict): + ''' + Mandatory fields from ContentHostingConfiguration structure in TS 26.512 + ''' + name: str + ingestConfiguration: IngestConfiguration + distributionConfigurations: List[DistributionConfiguration] + +class ContentHostingConfiguration(ContentHostingConfigurationMandatory, total=False): + ''' + ContentHostingConfiguration structure in TS 26.512 + ''' + entryPointPath: str + + @staticmethod + def fromJSON(chc_json: str) -> "ContentHostingConfiguration": + ''' + Generate a ContentHostingConfiguration structure from a JSON string + ''' + # parse the JSON + chc = json.loads(chc_json) + # convert enums + if 'distributionConfigurations' in chc: + for dist_conf in chc['distributionConfigurations']: + if 'supplementaryDistributionNetworks' in dist_conf: + for supp_net in dist_conf['supplementaryDistributionNetworks']: + supp_net['distributionNetworkType'] = DistributionNetworkType( + supp_net['distributionNetworkType']) + supp_net['distributionMode'] = DistributionMode( + supp_net['distributionMode']) + # Validate against ContentHostingConfiguration type + return ContentHostingConfiguration(chc) + + +# TS 29.571 ProblemDetail +class InvalidParamMandatory(TypedDict): + ''' + Mandatory fields from InvalidParam structure in TS 29.571 + ''' + param: str + +class InvalidParam(InvalidParamMandatory, total=False): + ''' + InvalidParam structure from TS 29.571 + ''' + reason: str + +class AccessTokenErrError(enum.Enum): + ''' + AccessTokenErrError enumeration from TS 29.571 + ''' + invalid_request = enum.auto() # pylint: disable=invalid-name + invalid_client = enum.auto() # pylint: disable=invalid-name + invalid_grant = enum.auto() # pylint: disable=invalid-name + unauthorized_client = enum.auto() # pylint: disable=invalid-name + unsupported_grant_type = enum.auto() # pylint: disable=invalid-name + invalid_scope = enum.auto() # pylint: disable=invalid-name + + def __str__(self): + return self.name + +class AccessTokenErrMandatory(TypedDict): + ''' + Mandatory fields from AccessTokenErr structure in TS 29.571 + ''' + error: AccessTokenErrError + +class AccessTokenErr(AccessTokenErrMandatory, total=False): + ''' + AccessTokenErr structure in TS 29.571 + ''' + error_description: str + error_uri: str + +class AccessTokenReqGrantType(enum.Enum): + ''' + AccessTokenReqGrantType enumeration in TS 29.571 + ''' + client_credentials = enum.auto() # pylint: disable=invalid-name + + def __str__(self): + return self.name + +class AccessTokenReqMandatory(TypedDict): + ''' + Mandatory fields from AccessTokenReq structure in TS 29.571 + ''' + grant_type: AccessTokenReqGrantType + nfInstanceId: str + scope: str + +class AccessTokenReq(AccessTokenReqMandatory, total=False): + ''' + AccessTokenReq structure in TS 29.571 + ''' + nfType: str + targetNfType: str + targetNfInstanceId: str + requesterPlmn: str + requesterPlmnList: List[str] + requesterSnssaiList: List[str] + requesterFqdn: str + requesterSnpnList: List[str] + targetPlmn: str + targetSnssaiList: List[str] + targetNsiList: List[str] + targetNfSetId: str + targetNfServiceSetId: str + hnrfAccessTokenUri: str + sourceNfInstanceId: str + +class ProblemDetail(TypedDict, total=False): + ''' + ProblemDetail structure in TS 29.571 + ''' + problemtype: str + title: str + status: int + detail: str + instance: str + cause: str + invalidParams: List[InvalidParam] + supportedFeatures: str + accessTokenError: AccessTokenErr + accessTokenRequest: AccessTokenReq + nrfId: str + + @staticmethod + def fromJSON(problem_detail_json: str): + ''' + Generate a ProblemDetail structure from a JSON string + ''' + prob_detail = json.loads(problem_detail_json) + if 'accessTokenError' in prob_detail: + for ate in prob_detail['accessTokenError']: + ate['error'] = AccessTokenErrError(ate['error']) + if 'accessTokenRequest' in prob_detail: + for atr in prob_detail['accessTokenRequest']: + atr['grant_type'] = AccessTokenReqGrantType(atr['grant_type']) + return prob_detail + +__all__ = [ + "ProblemDetail", + "AccessTokenErr", + "AccessTokenReq", + "InvalidParam", + "ApplicationId", + "ResourceId", + "ProvisioningSessionId", + "ProvisioningSessionType", + "ProvisioningSession", + "PROVISIONING_SESSION_TYPE_DOWNLINK", + "PROVISIONING_SESSION_TYPE_UPLINK", + ] diff --git a/tools/python3/m1_client_cli.py b/tools/python3/m1_client_cli.py new file mode 100755 index 0000000..3636b00 --- /dev/null +++ b/tools/python3/m1_client_cli.py @@ -0,0 +1,87 @@ +#!/usr/bin/python3 +#============================================================================== +# 5G-MAG Reference Tools: M1 Client CLI +#============================================================================== +# +# File: m1_client_cli.py +# License: 5G-MAG Public License (v1.0) +# Author: David Waring +# Copyright: (C) 2022 British Broadcasting Corporation +# +# For full license terms please see the LICENSE file distributed with this +# program. If this file is missing then the license can be retrieved from +# https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +# +#============================================================================== +# +# M1 Client CLI +# =============== +# +# This is a simple command line tool which will communicate with a 5GMS +# Application Function via the M1 interface. +# +'''5G-MAG Reference Tools: M1 Client CLI + +This provides a simple command line interface which can be used to manipulate +the configuration of a 5GMS Application Function via the M1 interface. +''' + +import asyncio +import sys + +from rt_m1_client import client as m1_client +from rt_m1_client.types import PROVISIONING_SESSION_TYPE_DOWNLINK +from rt_m1_client.exceptions import M1Error + +async def main(): + ''' + Async application entry point + ''' + try: + m1_session = m1_client.M1Client(('127.0.0.22', 7778)) + provisioning_session_response = await m1_session.createProvisioningSession( + PROVISIONING_SESSION_TYPE_DOWNLINK, 'myAppId', 'myAspId') + if provisioning_session_response is None: + print('Failed to create a provisioning session!') + return 1 + + provisioning_session_id = provisioning_session_response['ProvisioningSessionId'] + print(f'Provisioning Session {provisioning_session_id} created') + + certificate_resp = await m1_session.createServerCertificate(provisioning_session_id) + if certificate_resp is None: + print('Failed to create a server certificate') + return 1 + + certificate_id = certificate_resp['ServerCertificateId'] + print(f'Created certificate {certificate_id}') + + chc = { + 'name': 'Test CHC', + 'entryPointPath': 'BigBuckBunny_4s_onDemand_2014_05_09.mpd', + 'ingestConfiguration': { + 'pull': True, + 'protocol': 'urn:3gpp:5gms:content-protocol:http-pull-ingest', + 'baseURL': 'https://ftp.itec.aau.at/datasets/DASHDataset2014/BigBuckBunny/4sec/', + }, + 'distributionConfigurations': [ + { + 'certificateId': certificate_id, + } + ] + } + result = await m1_session.createContentHostingConfiguration(provisioning_session_id, chc) + print(f'Created CHC: {repr(result)}') + except M1Error as err: + print(f'Communication error: {err}') + return 2 + return 0 + +def app(): + ''' + Application entry point + ''' + return asyncio.run(main()) + +if __name__ == '__main__': + sys.exit(app()) diff --git a/tools/python3/pylint.rc b/tools/python3/pylint.rc new file mode 100644 index 0000000..a338feb --- /dev/null +++ b/tools/python3/pylint.rc @@ -0,0 +1,615 @@ +[MAIN] + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Load and enable all available extensions. Use --list-extensions to see a list +# all available extensions. +#enable-all-extensions= + +# In error mode, messages with a category besides ERROR or FATAL are +# suppressed, and no reports are done by default. Error mode is compatible with +# disabling specific errors. +#errors-only= + +# Always return a 0 (non-error) status code, even if lint errors are found. +# This is primarily useful in continuous integration scripts. +#exit-zero= + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. +extension-pkg-allow-list= + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. (This is an alternative name to extension-pkg-allow-list +# for backward compatibility.) +extension-pkg-whitelist= + +# Return non-zero exit code if any of these messages/categories are detected, +# even if score is above --fail-under value. Syntax same as enable. Messages +# specified are enabled, while categories only check already-enabled messages. +fail-on= + +# Specify a score threshold to be exceeded before program exits with error. +fail-under=10 + +# Interpret the stdin as a python script, whose filename needs to be passed as +# the module_or_package argument. +#from-stdin= + +# Files or directories to be skipped. They should be base names, not paths. +ignore=CVS + +# Add files or directories matching the regex patterns to the ignore-list. The +# regex matches against paths and can be in Posix or Windows format. +ignore-paths= + +# Files or directories matching the regex patterns are skipped. The regex +# matches against base names, not paths. The default value ignores Emacs file +# locks +ignore-patterns=^\.# + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis). It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the +# number of processors available to use, and will cap the count on Windows to +# avoid hangs. +jobs=1 + +# Control the amount of potential inferred values when inferring a single +# object. This can help the performance when dealing with large functions or +# complex, nested conditions. +limit-inference-results=100 + +# List of plugins (as comma separated values of python module names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. +persistent=yes + +# Minimum Python version to use for version dependent checks. Will default to +# the version used to run pylint. +py-version=3.11 + +# Discover python modules and packages in the file system subtree. +recursive=no + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages. +suggestion-mode=yes + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + +# In verbose mode, extra non-checker-related info will be displayed. +#verbose= + + +[REPORTS] + +# Python expression which should return a score less than or equal to 10. You +# have access to the variables 'fatal', 'error', 'warning', 'refactor', +# 'convention', and 'info' which contain the number of messages in each +# category, as well as 'statement' which is the total number of statements +# analyzed. This score is used by the global evaluation report (RP0004). +evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details. +msg-template= + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio). You can also give a reporter class, e.g. +# mypackage.mymodule.MyReporterClass. +#output-format= + +# Tells whether to display a full report or only the messages. +reports=no + +# Activate the evaluation score. +score=yes + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE, +# UNDEFINED. +confidence=HIGH, + CONTROL_FLOW, + INFERENCE, + INFERENCE_FAILURE, + UNDEFINED + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once). You can also use "--disable=all" to +# disable everything first and then re-enable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use "--disable=all --enable=classes +# --disable=W". +disable=raw-checker-failed, + bad-inline-option, + locally-disabled, + file-ignored, + suppressed-message, + useless-suppression, + deprecated-pragma, + use-symbolic-message-instead + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable=c-extension-no-member + + +[BASIC] + +# Naming style matching correct argument names. +argument-naming-style=snake_case + +# Regular expression matching correct argument names. Overrides argument- +# naming-style. If left empty, argument names will be checked with the set +# naming style. +#argument-rgx= + +# Naming style matching correct attribute names. +attr-naming-style=snake_case + +# Regular expression matching correct attribute names. Overrides attr-naming- +# style. If left empty, attribute names will be checked with the set naming +# style. +#attr-rgx= + +# Bad variable names which should always be refused, separated by a comma. +bad-names=foo, + bar, + baz, + toto, + tutu, + tata + +# Bad variable names regexes, separated by a comma. If names match any regex, +# they will always be refused +bad-names-rgxs= + +# Naming style matching correct class attribute names. +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style. If left empty, class attribute names will be checked +# with the set naming style. +#class-attribute-rgx= + +# Naming style matching correct class constant names. +class-const-naming-style=UPPER_CASE + +# Regular expression matching correct class constant names. Overrides class- +# const-naming-style. If left empty, class constant names will be checked with +# the set naming style. +#class-const-rgx= + +# Naming style matching correct class names. +class-naming-style=PascalCase + +# Regular expression matching correct class names. Overrides class-naming- +# style. If left empty, class names will be checked with the set naming style. +#class-rgx= + +# Naming style matching correct constant names. +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names. Overrides const-naming- +# style. If left empty, constant names will be checked with the set naming +# style. +#const-rgx= + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming style matching correct function names. +function-naming-style=snake_case + +# Regular expression matching correct function names. Overrides function- +# naming-style. If left empty, function names will be checked with the set +# naming style. +#function-rgx= + +# Good variable names which should always be accepted, separated by a comma. +good-names=i, + j, + k, + ex, + Run, + _ + +# Good variable names regexes, separated by a comma. If names match any regex, +# they will always be accepted +good-names-rgxs= + +# Include a hint for the correct naming format with invalid-name. +include-naming-hint=no + +# Naming style matching correct inline iteration names. +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style. If left empty, inline iteration names will be checked +# with the set naming style. +#inlinevar-rgx= + +# Naming style matching correct method names. +#method-naming-style=camelCase + +# Regular expression matching correct method names. Overrides method-naming- +# style. If left empty, method names will be checked with the set naming style. +method-rgx=^(?:__[a-zA-Z][a-zA-Z0-9_]*|_?[a-z][a-zA-Z0-9]*)$ + +# Naming style matching correct module names. +module-naming-style=snake_case + +# Regular expression matching correct module names. Overrides module-naming- +# style. If left empty, module names will be checked with the set naming style. +#module-rgx= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +# These decorators are taken in consideration only for invalid-name. +property-classes=abc.abstractproperty + +# Regular expression matching correct type variable names. If left empty, type +# variable names will be checked with the set naming style. +#typevar-rgx= + +# Naming style matching correct variable names. +variable-naming-style=snake_case + +# Regular expression matching correct variable names. Overrides variable- +# naming-style. If left empty, variable names will be checked with the set +# naming style. +#variable-rgx= + + +[CLASSES] + +# Warn about protected attribute access inside special methods +check-protected-access-in-special-methods=no + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp, + __post_init__ + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict, + _fields, + _replace, + _source, + _make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=cls + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=sys.exit,argparse.parse_error + + +[DESIGN] + +# List of regular expressions of class ancestor names to ignore when counting +# public methods (see R0903) +exclude-too-few-public-methods= + +# List of qualified class names to ignore when counting class parents (see +# R0901) +ignored-parents= + +# Maximum number of arguments for function / method. +max-args=5 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Maximum number of boolean expressions in an if statement (see R0916). +max-bool-expr=5 + +# Maximum number of branch for function / method body. +max-branches=12 + +# Maximum number of locals for function / method body. +max-locals=15 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body. +max-returns=6 + +# Maximum number of statements in function / method body. +max-statements=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when caught. +overgeneral-exceptions=BaseException, + Exception + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=100 + +# Maximum number of lines in a module. +max-module-lines=1000 + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[IMPORTS] + +# List of modules that can be imported at any level, not just the top level +# one. +allow-any-import-level= + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Deprecated modules which should not be used, separated by a comma. +deprecated-modules= + +# Output a graph (.gv or any supported image format) of external dependencies +# to the given file (report RP0402 must not be disabled). +ext-import-graph= + +# Output a graph (.gv or any supported image format) of all (i.e. internal and +# external) dependencies to the given file (report RP0402 must not be +# disabled). +import-graph= + +# Output a graph (.gv or any supported image format) of internal dependencies +# to the given file (report RP0402 must not be disabled). +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + +# Couples of modules and preferred modules, separated by a comma. +preferred-modules= + + +[LOGGING] + +# The type of string formatting that logging methods do. `old` means using % +# formatting, `new` is for `{}` formatting. +logging-format-style=old + +# Logging modules to check that the string format arguments are in logging +# function parameter format. +logging-modules=logging + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME, + XXX, + TODO + +# Regular expression of note tags to take in consideration. +notes-rgx= + + +[SIMILARITIES] + +# Comments are removed from the similarity computation +ignore-comments=yes + +# Docstrings are removed from the similarity computation +ignore-docstrings=yes + +# Imports are removed from the similarity computation +ignore-imports=yes + +# Signatures are removed from the similarity computation +ignore-signatures=yes + +# Minimum lines number of a similarity. +min-similarity-lines=4 + + +[SPELLING] + +# Limits count of emitted suggestions for spelling mistakes. +max-spelling-suggestions=4 + +# Spelling dictionary name. Available dictionaries: en_AG (hunspell), en_AU +# (hunspell), en_BS (hunspell), en_BW (hunspell), en_BZ (hunspell), en_CA +# (hunspell), en_DK (hunspell), en_GB (hunspell), en_GH (hunspell), en_HK +# (hunspell), en_IE (hunspell), en_IN (hunspell), en_JM (hunspell), en_MW +# (hunspell), en_NA (hunspell), en_NG (hunspell), en_NZ (hunspell), en_PH +# (hunspell), en_SG (hunspell), en_TT (hunspell), en_US (hunspell), en_ZA +# (hunspell), en_ZM (hunspell), en_ZW (hunspell). +spelling-dict= + +# List of comma separated words that should be considered directives if they +# appear at the beginning of a comment and should not be checked. +spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains the private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to the private dictionary (see the +# --spelling-private-dict-file option) instead of raising a message. +spelling-store-unknown-words=no + + +[STRING] + +# This flag controls whether inconsistent-quotes generates a warning when the +# character used as a quote delimiter is used inconsistently within a module. +check-quote-consistency=no + +# This flag controls whether the implicit-str-concat should generate a warning +# on implicit string concatenation in sequences defined over several lines. +check-str-concat-over-line-jumps=no + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# Tells whether to warn about missing members when the owner of the attribute +# is inferred to be None. +ignore-none=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of symbolic message names to ignore for Mixin members. +ignored-checks-for-mixins=no-member, + not-async-context-manager, + not-context-manager, + attribute-defined-outside-init + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + +# Regex pattern to define which classes are considered mixins. +mixin-class-rgx=.*[Mm]ixin + +# List of decorators that change the signature of a decorated function. +signature-mutators= + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid defining new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of names allowed to shadow builtins +allowed-redefined-builtins= + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_, + _cb + +# A regular expression matching the name of dummy variables (i.e. expected to +# not be used). +dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore. +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io From dfeb09f7b560048dcfb4a3c346d102d39934cdd7 Mon Sep 17 00:00:00 2001 From: deva Date: Mon, 6 Mar 2023 08:24:18 +0000 Subject: [PATCH 16/48] Introduce seperate state management for the M1 Management Interface --- src/5gmsaf/af-sm-msaf.c | 269 ++++++++++++++++++++++++ src/5gmsaf/context.c | 44 +++- src/5gmsaf/context.h | 4 + src/5gmsaf/event.c | 37 ++++ src/5gmsaf/event.h | 4 + src/5gmsaf/init.c | 17 +- src/5gmsaf/meson.build | 2 + src/5gmsaf/msaf-mgmt-sm.c | 333 ++++++++++++++++++++++++++++++ src/5gmsaf/msaf-mgmt-sm.h | 31 +++ src/5gmsaf/msaf-sm.c | 81 +++++++- src/5gmsaf/provisioning-session.c | 61 +++++- src/5gmsaf/provisioning-session.h | 4 + src/5gmsaf/sbi-path.c | 2 +- 13 files changed, 873 insertions(+), 16 deletions(-) create mode 100644 src/5gmsaf/af-sm-msaf.c create mode 100644 src/5gmsaf/msaf-mgmt-sm.c create mode 100644 src/5gmsaf/msaf-mgmt-sm.h diff --git a/src/5gmsaf/af-sm-msaf.c b/src/5gmsaf/af-sm-msaf.c new file mode 100644 index 0000000..6aced82 --- /dev/null +++ b/src/5gmsaf/af-sm-msaf.c @@ -0,0 +1,269 @@ +/* + * License: 5G-MAG Public License (v1.0) + * Copyright: (C) 2022 British Broadcasting Corporation + * + * For full license terms please see the LICENSE file distributed with this + * program. If this file is missing then the license can be retrieved from + * https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view + */ + + +#include "ogs-sbi.h" +#include "sbi-path.h" +#include "context.h" +#include "server.h" + + +void af_state_initial(ogs_fsm_t *s, msaf_event_t *e) +{ + msaf_sm_debug(e); + + ogs_assert(s); + + OGS_FSM_TRAN(s, &af_state_functional); +} + +void af_state_final(ogs_fsm_t *s, af_event_t *e) +{ + af_sm_debug(e); + + ogs_assert(s); +} + +void af_state_functional(ogs_fsm_t *s, af_event_t *e) +{ + int rv; + + ogs_sbi_stream_t *stream = NULL; + ogs_sbi_request_t *request = NULL; + + ogs_sbi_nf_instance_t *nf_instance = NULL; + ogs_sbi_subscription_data_t *subscription_data = NULL; + ogs_sbi_response_t *response = NULL; + ogs_sbi_message_t message; + ogs_sbi_xact_t *sbi_xact = NULL; + + af_sm_debug(e); + + ogs_assert(s); + + msaf_context_server_name_set(); + + switch (e->h.id) { + case OGS_FSM_ENTRY_SIG: + ogs_info("[%s] AF Running", ogs_sbi_self()->nf_instance->id); + + break; + + case OGS_FSM_EXIT_SIG: + break; + + case OGS_EVENT_SBI_SERVER: + request = e->h.sbi.request; + ogs_assert(request); + stream = e->h.sbi.data; + ogs_assert(stream); + + ogs_info("AF SM"); + + rv = ogs_sbi_parse_header(&message, &request->h); + if (rv != OGS_OK) { + ogs_error("ogs_sbi_parse_header() failed"); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "cannot parse HTTP message", NULL, NULL, NULL, app_meta)); + + break; + } + + SWITCH(message.h.service.name) + CASE(OGS_SBI_SERVICE_NAME_NNRF_NFM) + if (strcmp(message.h.api.version, OGS_SBI_API_V1) != 0) { + ogs_error("Not supported version [%s]", message.h.api.version); + ogs_assert(true == ogs_sbi_server_send_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + &message, "Not supported version", NULL)); + ogs_sbi_message_free(&message); + break; + } + SWITCH(message.h.resource.component[0]) + CASE(OGS_SBI_RESOURCE_NAME_NF_STATUS_NOTIFY) + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) + ogs_nnrf_nfm_handle_nf_status_notify(stream, &message); + break; + + DEFAULT + ogs_error("Invalid HTTP method [%s]", message.h.method); + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_FORBIDDEN, &message, + "Invalid HTTP method", message.h.method)); + END + break; + + DEFAULT + ogs_error("Invalid resource name [%s]", + message.h.resource.component[0]); + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_BAD_REQUEST, &message, + "Invalid resource name", + message.h.resource.component[0])); + END + ogs_sbi_message_free(&message); + break; + + DEFAULT + ogs_error("Invalid API name [%s]", message.h.service.name); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid API name.", message.h.service.name, NULL, NULL, app_meta)); + + END + break; + + case OGS_EVENT_SBI_CLIENT: + ogs_assert(e); + + response = e->h.sbi.response; + ogs_assert(response); + rv = ogs_sbi_parse_header(&message, &response->h); + if (rv != OGS_OK) { + ogs_error("ogs_sbi_parse_header() failed"); + ogs_sbi_message_free(&message); + ogs_sbi_response_free(response); + break; + } + { + ogs_hash_index_t *hi; + for (hi = ogs_hash_first(response->http.headers); + hi; hi = ogs_hash_next(hi)) { + if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { + message.http.content_type = ogs_hash_this_val(hi); + } else if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_LOCATION)) { + message.http.location = ogs_hash_this_val(hi); + } + } + } + + message.res_status = response->status; + + SWITCH(message.h.service.name) + + CASE(OGS_SBI_SERVICE_NAME_NNRF_NFM) + + SWITCH(message.h.resource.component[0]) + CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES) + nf_instance = e->h.sbi.data; + ogs_assert(nf_instance); + ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); + + e->h.sbi.message = &message; + ogs_fsm_dispatch(&nf_instance->sm, e); + break; + + CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS) + subscription_data = e->h.sbi.data; + ogs_assert(subscription_data); + + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) + if (message.res_status == OGS_SBI_HTTP_STATUS_CREATED || + message.res_status == OGS_SBI_HTTP_STATUS_OK) { + ogs_nnrf_nfm_handle_nf_status_subscribe( + subscription_data, &message); + } else { + ogs_error("HTTP response error : %d", + message.res_status); + } + break; + + CASE(OGS_SBI_HTTP_METHOD_DELETE) + if (message.res_status == OGS_SBI_HTTP_STATUS_NO_CONTENT) { + ogs_sbi_subscription_data_remove(subscription_data); + } else { + ogs_error("HTTP response error : %d", + message.res_status); + } + break; + + DEFAULT + ogs_error("Invalid HTTP method [%s]", message.h.method); + ogs_assert_if_reached(); + END + break; + + DEFAULT + ogs_error("Invalid resource name [%s]", + message.h.resource.component[0]); + ogs_assert_if_reached(); + END + break; + + DEFAULT + ogs_error("Invalid service name [%s]", message.h.service.name); + ogs_assert_if_reached(); + END + + ogs_sbi_message_free(&message); + ogs_sbi_response_free(response); + break; + + case OGS_EVENT_SBI_TIMER: + ogs_assert(e); + + switch(e->h.timer_id) { + case OGS_TIMER_NF_INSTANCE_REGISTRATION_INTERVAL: + case OGS_TIMER_NF_INSTANCE_HEARTBEAT_INTERVAL: + case OGS_TIMER_NF_INSTANCE_NO_HEARTBEAT: + case OGS_TIMER_NF_INSTANCE_VALIDITY: + nf_instance = e->h.sbi.data; + ogs_assert(nf_instance); + ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); + + ogs_fsm_dispatch(&nf_instance->sm, e); + if (OGS_FSM_CHECK(&nf_instance->sm, ogs_sbi_nf_state_exception)) + ogs_error("State machine exception [%d]", e->h.timer_id); + break; + + case OGS_TIMER_SUBSCRIPTION_VALIDITY: + subscription_data = e->h.sbi.data; + ogs_assert(subscription_data); + + ogs_assert(true == + ogs_nnrf_nfm_send_nf_status_subscribe(subscription_data)); + + ogs_debug("Subscription validity expired [%s]", + subscription_data->id); + ogs_sbi_subscription_data_remove(subscription_data); + break; + + case OGS_TIMER_SBI_CLIENT_WAIT: + sbi_xact = e->h.sbi.data; + ogs_assert(sbi_xact); + + stream = sbi_xact->assoc_stream; + + ogs_sbi_xact_remove(sbi_xact); + + ogs_error("Cannot receive SBI message"); + if (stream) { + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_GATEWAY_TIMEOUT, NULL, + "Cannot receive SBI message", NULL)); + } + break; + + default: + ogs_error("Unknown timer[%s:%d]", + ogs_timer_get_name(e->h.timer_id), e->h.timer_id); + } + break; + + default: + ogs_error("No handler for event %s", msaf_event_get_name(e)); + break; + } + ogs_free(nf_name); +} + +/* vim:ts=8:sts=4:sw=4:expandtab: +*/ diff --git a/src/5gmsaf/context.c b/src/5gmsaf/context.c index 827a500..fd35298 100644 --- a/src/5gmsaf/context.c +++ b/src/5gmsaf/context.c @@ -39,8 +39,7 @@ static void msaf_context_application_server_state_assigned_provisioning_sessions static void msaf_context_application_server_state_remove_all(void); static void msaf_context_server_addr_remove_all(void); static void msaf_context_server_addr_remove(msaf_context_server_addr_t *msaf_server_addr); - -/***** Public functions *****/ +static void msaf_context_server_sockaddr_remove(void); void msaf_context_init(void) { @@ -64,6 +63,11 @@ void msaf_context_init(void) self->content_hosting_configuration_file_map = ogs_hash_make(); ogs_assert(self->content_hosting_configuration_file_map); + self->config.app_server_sockaddr = NULL; + self->config.mgmt_server_sockaddr = NULL; + self->config.app_server_sockaddr_v6 = NULL; + self->config.mgmt_server_sockaddr_v6 = NULL; + msaf_server_response_cache_control_set(); } @@ -97,7 +101,7 @@ void msaf_context_final(void) if (self->config.certificateManager) ogs_free(self->config.certificateManager); - + msaf_context_server_addr_remove_all(); msaf_application_server_remove_all(); @@ -110,6 +114,8 @@ void msaf_context_final(void) msaf_context_application_server_state_remove_all(); + msaf_context_server_sockaddr_remove(); + ogs_free(self); self = NULL; } @@ -212,7 +218,7 @@ int msaf_context_parse_config(void) } msaf_server_response_cache_control_set_from_config(m1_provisioning_session_response_max_age, m1_content_hosting_configurations_response_max_age, m1_server_certificates_response_max_age, m1_content_protocols_response_max_age, m5_service_access_information_response_max_age); - } else if (!strcmp(msaf_key, "sbi")) { + } else if (!strcmp(msaf_key, "sbi") || !strcmp(msaf_key, "m1ManagementInterface")) { if(!self->config.open5gsIntegration_flag) { ogs_list_t list, list6; ogs_socknode_t *node = NULL, *node6 = NULL; @@ -318,6 +324,10 @@ int msaf_context_parse_config(void) } else ogs_warn("unknown key `%s`", sbi_key); } + + if (!strcmp(msaf_key, "m1ManagementInterface") && (port == 0)){ + ogs_warn("Specify the [%s] port, otherwise a random port will be used", msaf_key); + } addr = NULL; for (i = 0; i < num; i++) { @@ -357,13 +367,23 @@ int msaf_context_parse_config(void) ogs_sbi_server_t *server = ogs_sbi_server_add( node->addr, is_option ? &option : NULL); ogs_assert(server); - + if (addr && ogs_app()->parameter.no_ipv4 == 0) ogs_sbi_server_set_advertise( server, AF_INET, addr); if (key) server->tls.key = key; if (pem) server->tls.pem = pem; + + if (!strcmp(msaf_key, "sbi")) { + + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.app_server_sockaddr, server->node.addr)); + + } + if (!strcmp(msaf_key, "m1ManagementInterface")) { + + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.mgmt_server_sockaddr, server->node.addr)); + } } node6 = ogs_list_first(&list6); if (node6) { @@ -377,6 +397,13 @@ int msaf_context_parse_config(void) if (key) server->tls.key = key; if (pem) server->tls.pem = pem; + if (!strcmp(msaf_key, "sbi")) { + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.app_server_sockaddr_v6, server->node.addr)); + } + if (!strcmp(msaf_key, "m1ManagementInterface")) { + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.mgmt_server_sockaddr_v6, server->node.addr)); + } + } if (addr) @@ -541,6 +568,13 @@ static void msaf_context_application_server_state_remove_all(void) { } } +static void msaf_context_server_sockaddr_remove(void){ + if(self->config.app_server_sockaddr) ogs_freeaddrinfo(self->config.app_server_sockaddr); + if(self->config.mgmt_server_sockaddr) ogs_freeaddrinfo(self->config.mgmt_server_sockaddr); + if(self->config.app_server_sockaddr_v6) ogs_freeaddrinfo(self->config.app_server_sockaddr_v6); + if(self->config.mgmt_server_sockaddr_v6) ogs_freeaddrinfo(self->config.app_server_sockaddr_v6); +} + static int msaf_context_prepare(void) { return OGS_OK; diff --git a/src/5gmsaf/context.h b/src/5gmsaf/context.h index 50f2d59..aca7a20 100644 --- a/src/5gmsaf/context.h +++ b/src/5gmsaf/context.h @@ -49,6 +49,10 @@ typedef struct msaf_configuration_s { ogs_list_t applicationServers_list; ogs_list_t server_addr_list; // Nodes for this list are of type msaf_sbi_addr_t * char *certificateManager; + ogs_sockaddr_t *app_server_sockaddr; + ogs_sockaddr_t *mgmt_server_sockaddr; + ogs_sockaddr_t *app_server_sockaddr_v6; + ogs_sockaddr_t *mgmt_server_sockaddr_v6; msaf_server_response_cache_control_t *server_response_cache_control; int number_of_application_servers; } msaf_configuration_t; diff --git a/src/5gmsaf/event.c b/src/5gmsaf/event.c index bcb845b..bc9575b 100644 --- a/src/5gmsaf/event.c +++ b/src/5gmsaf/event.c @@ -27,3 +27,40 @@ const char *msaf_event_get_name(msaf_event_t *e) return ogs_event_get_name(&e->h); } + +int get_server_type_from_event(msaf_event_t *e) +{ + ogs_sbi_stream_t *stream = NULL; + ogs_sbi_server_t *server = NULL; + + stream = e->h.sbi.data; + ogs_assert(stream); + + server = ogs_sbi_server_from_stream(stream); + ogs_assert(server); + + if (ogs_sockaddr_is_equal(server->node.addr, msaf_self()->config.app_server_sockaddr) == true) { + ogs_info("returns MSAF_APP_SERVER"); + return MSAF_APP_SERVER; + } + + if (ogs_sockaddr_is_equal(server->node.addr, msaf_self()->config.mgmt_server_sockaddr) == true) { + ogs_info("returns MSAF_MGMT_SERVER"); + return MSAF_MGMT_SERVER; + } + + if (ogs_sockaddr_is_equal(server->node.addr, msaf_self()->config.app_server_sockaddr_v6) == true) { + ogs_info("returns MSAF_APP_SERVER"); + return MSAF_APP_SERVER; + } + + if (ogs_sockaddr_is_equal(server->node.addr, msaf_self()->config.mgmt_server_sockaddr_v6) == true) { + ogs_info("returns MSAF_MGMT_SERVER"); + return MSAF_MGMT_SERVER; + + } + + return MSAF_APP_SERVER; + +} + diff --git a/src/5gmsaf/event.h b/src/5gmsaf/event.h index c424b0b..7e8589d 100644 --- a/src/5gmsaf/event.h +++ b/src/5gmsaf/event.h @@ -15,6 +15,8 @@ program. If this file is missing then the license can be retrieved from #include "ogs-sbi.h" #include "context.h" +#define MSAF_APP_SERVER 0 +#define MSAF_MGMT_SERVER 1 #ifdef __cplusplus extern "C" { @@ -56,6 +58,8 @@ typedef struct msaf_event_s { OGS_STATIC_ASSERT(OGS_EVENT_SIZE >= sizeof(msaf_event_t)); extern const char *msaf_event_get_name(msaf_event_t *e); +extern int get_server_type_from_event(msaf_event_t *e); + #ifdef __cplusplus } diff --git a/src/5gmsaf/init.c b/src/5gmsaf/init.c index 10e9598..180f491 100644 --- a/src/5gmsaf/init.c +++ b/src/5gmsaf/init.c @@ -10,7 +10,7 @@ program. If this file is missing then the license can be retrieved from #include "context.h" #include "sbi-path.h" - +#include "msaf-mgmt-sm.h" #include "init.h" static ogs_thread_t *thread; @@ -95,9 +95,13 @@ void msaf_terminate(void) static void msaf_main(void *data) { ogs_fsm_t msaf_sm; + ogs_fsm_t msaf_mgmt_sm; int rv; ogs_fsm_init(&msaf_sm, msaf_state_initial, msaf_state_final, 0); + if(msaf_self()->config.mgmt_server_sockaddr || msaf_self()->config.mgmt_server_sockaddr_v6) { + ogs_fsm_init(&msaf_mgmt_sm, msaf_mgmt_state_initial, msaf_mgmt_state_final, 0); + } for ( ;; ) { ogs_pollset_poll(ogs_app()->pollset, @@ -118,13 +122,22 @@ static void msaf_main(void *data) break; ogs_assert(e); - ogs_fsm_dispatch(&msaf_sm, e); + rv = get_server_type_from_event(e); + if (rv == MSAF_APP_SERVER) { + ogs_fsm_dispatch(&msaf_sm, e); + } + if(rv == MSAF_MGMT_SERVER) { + ogs_fsm_dispatch(&msaf_mgmt_sm, e); + } ogs_event_free(e); } } done: ogs_fsm_fini(&msaf_sm, 0); + if(msaf_self()->config.mgmt_server_sockaddr || msaf_self()->config.mgmt_server_sockaddr_v6) { + ogs_fsm_fini(&msaf_mgmt_sm, 0); + } } static int msaf_set_time(void) diff --git a/src/5gmsaf/meson.build b/src/5gmsaf/meson.build index d252496..cb1fa70 100644 --- a/src/5gmsaf/meson.build +++ b/src/5gmsaf/meson.build @@ -44,6 +44,8 @@ libmsaf_dist_sources = files(''' sbi-path.h service-access-information.h service-access-information.c + msaf-mgmt-sm.c + msaf-mgmt-sm.h msaf-sm.c msaf-sm.h utilities.h diff --git a/src/5gmsaf/msaf-mgmt-sm.c b/src/5gmsaf/msaf-mgmt-sm.c new file mode 100644 index 0000000..b8905a4 --- /dev/null +++ b/src/5gmsaf/msaf-mgmt-sm.c @@ -0,0 +1,333 @@ +/* + * License: 5G-MAG Public License (v1.0) + * Copyright: (C) 2022 British Broadcasting Corporation + * + * For full license terms please see the LICENSE file distributed with this + * program. If this file is missing then the license can be retrieved from + * https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view + */ + +#include "ogs-sbi.h" +#include "sbi-path.h" +#include "context.h" +#include "certmgr.h" +#include "server.h" +#include "response-cache-control.h" +#include "msaf-version.h" +#include "msaf-mgmt-sm.h" +#include "openapi/api/TS26512_M1_ProvisioningSessionsAPI-info.h" + +const nf_server_interface_metadata_t +m1_mgmt_provisioningsession_api_metadata = { + M1_PROVISIONINGSESSIONS_API_NAME, + M1_PROVISIONINGSESSIONS_API_VERSION +}; + +void msaf_mgmt_state_initial(ogs_fsm_t *s, msaf_event_t *e) +{ + msaf_sm_debug(e); + + ogs_assert(s); + + OGS_FSM_TRAN(s, &msaf_mgmt_state_functional); +} + +void msaf_mgmt_state_final(ogs_fsm_t *s, msaf_event_t *e) +{ + msaf_sm_debug(e); + + ogs_assert(s); +} + +void msaf_mgmt_state_functional(ogs_fsm_t *s, msaf_event_t *e) +{ + int rv; + + ogs_sbi_stream_t *stream = NULL; + ogs_sbi_request_t *request = NULL; + + ogs_sbi_nf_instance_t *nf_instance = NULL; + ogs_sbi_subscription_data_t *subscription_data = NULL; + ogs_sbi_response_t *response = NULL; + ogs_sbi_message_t message; + ogs_sbi_xact_t *sbi_xact = NULL; + + msaf_sm_debug(e); + + msaf_context_server_name_set(); + char *nf_name = ogs_msprintf("5GMSdAF-%s", msaf_self()->server_name); + const nf_server_app_metadata_t app_metadata = { MSAF_NAME, MSAF_VERSION, nf_name}; + const nf_server_interface_metadata_t *m1_provisioningsession_api = &m1_mgmt_provisioningsession_api_metadata; + const nf_server_app_metadata_t *app_meta = &app_metadata; + + ogs_assert(s); + + switch (e->h.id) { + case OGS_FSM_ENTRY_SIG: + ogs_info("[%s] MSAF Management Interface Running", ogs_sbi_self()->nf_instance->id); + break; + + case OGS_FSM_EXIT_SIG: + break; + + case OGS_EVENT_SBI_SERVER: + request = e->h.sbi.request; + ogs_assert(request); + stream = e->h.sbi.data; + ogs_assert(stream); + + rv = ogs_sbi_parse_header(&message, &request->h); + if (rv != OGS_OK) { + ogs_error("ogs_sbi_parse_header() failed"); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "cannot parse HTTP message", NULL, NULL, NULL, app_meta)); + + break; + } + + SWITCH(message.h.service.name) + CASE(OGS_SBI_SERVICE_NAME_NNRF_NFM) + if (strcmp(message.h.api.version, OGS_SBI_API_V1) != 0) { + ogs_error("Not supported version [%s]", message.h.api.version); + ogs_assert(true == ogs_sbi_server_send_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + &message, "Not supported version", NULL)); + ogs_sbi_message_free(&message); + break; + } + SWITCH(message.h.resource.component[0]) + CASE(OGS_SBI_RESOURCE_NAME_NF_STATUS_NOTIFY) + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) + ogs_nnrf_nfm_handle_nf_status_notify(stream, &message); + break; + + DEFAULT + ogs_error("Invalid HTTP method [%s]", message.h.method); + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_FORBIDDEN, &message, + "Invalid HTTP method", message.h.method)); + END + break; + + DEFAULT + ogs_error("Invalid resource name [%s]", + message.h.resource.component[0]); + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_BAD_REQUEST, &message, + "Invalid resource name", + message.h.resource.component[0])); + END + ogs_sbi_message_free(&message); + break; + + CASE("5gmag-rt-management") + if (strcmp(message.h.api.version, "v1") != 0) { + char *error; + ogs_error("Not supported version [%s]", message.h.api.version); + + error = ogs_msprintf("Version [%s] not supported", message.h.api.version); + + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL, app_meta)); + + ogs_sbi_message_free(&message); + ogs_free(error); + break; + } + + SWITCH(message.h.resource.component[0]) + + CASE("provisioning-sessions") + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_GET) + char *provisioning_sessions; + ogs_sbi_response_t *response; + provisioning_sessions = enumerate_provisioning_sessions(); + if (provisioning_sessions) { + response = nf_server_new_response(NULL, "application/json", NULL, NULL, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, NULL, app_meta); + + nf_server_populate_response(response, strlen(provisioning_sessions), ogs_strdup(provisioning_sessions), 200); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + if (strcmp(provisioning_sessions,"[]")) ogs_free(provisioning_sessions); + break; + } else { + ogs_error("Internal Server Error."); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR, 0, &message, "Internal Server Error.", message.h.method, NULL, NULL, app_meta)); + + } + DEFAULT + ogs_error("Invalid HTTP method [%s]", message.h.method); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 1, &message, "Invalid HTTP method.", message.h.method, NULL, NULL, app_meta)); + END + break; + DEFAULT + char *err; + ogs_error("Invalid resource name [%s]", + message.h.resource.component[0]); + asprintf(&err,"Invalid resource name [%s]", message.h.resource.component[0]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid resource name", err, NULL, NULL, app_meta)); + + + END + ogs_sbi_message_free(&message); + break; + + + + DEFAULT + ogs_error("Invalid API name [%s]", message.h.service.name); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid API name.", message.h.service.name, NULL, NULL, app_meta)); + + END + break; + + case OGS_EVENT_SBI_CLIENT: + ogs_assert(e); + + response = e->h.sbi.response; + ogs_assert(response); + rv = ogs_sbi_parse_header(&message, &response->h); + if (rv != OGS_OK) { + ogs_error("ogs_sbi_parse_header() failed"); + ogs_sbi_message_free(&message); + ogs_sbi_response_free(response); + break; + } + { + ogs_hash_index_t *hi; + for (hi = ogs_hash_first(response->http.headers); + hi; hi = ogs_hash_next(hi)) { + if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { + message.http.content_type = ogs_hash_this_val(hi); + } else if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_LOCATION)) { + message.http.location = ogs_hash_this_val(hi); + } + } + } + + message.res_status = response->status; + + SWITCH(message.h.service.name) + + CASE(OGS_SBI_SERVICE_NAME_NNRF_NFM) + + SWITCH(message.h.resource.component[0]) + CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES) + nf_instance = e->h.sbi.data; + ogs_assert(nf_instance); + ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); + + e->h.sbi.message = &message; + ogs_fsm_dispatch(&nf_instance->sm, e); + break; + + CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS) + subscription_data = e->h.sbi.data; + ogs_assert(subscription_data); + + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) + if (message.res_status == OGS_SBI_HTTP_STATUS_CREATED || + message.res_status == OGS_SBI_HTTP_STATUS_OK) { + ogs_nnrf_nfm_handle_nf_status_subscribe( + subscription_data, &message); + } else { + ogs_error("HTTP response error : %d", + message.res_status); + } + break; + + CASE(OGS_SBI_HTTP_METHOD_DELETE) + if (message.res_status == OGS_SBI_HTTP_STATUS_NO_CONTENT) { + ogs_sbi_subscription_data_remove(subscription_data); + } else { + ogs_error("HTTP response error : %d", + message.res_status); + } + break; + + DEFAULT + ogs_error("Invalid HTTP method [%s]", message.h.method); + ogs_assert_if_reached(); + END + break; + + DEFAULT + ogs_error("Invalid resource name [%s]", + message.h.resource.component[0]); + ogs_assert_if_reached(); + END + break; + + DEFAULT + ogs_error("Invalid service name [%s]", message.h.service.name); + ogs_assert_if_reached(); + END + + ogs_sbi_message_free(&message); + ogs_sbi_response_free(response); + break; + + case OGS_EVENT_SBI_TIMER: + ogs_assert(e); + + switch(e->h.timer_id) { + case OGS_TIMER_NF_INSTANCE_REGISTRATION_INTERVAL: + case OGS_TIMER_NF_INSTANCE_HEARTBEAT_INTERVAL: + case OGS_TIMER_NF_INSTANCE_NO_HEARTBEAT: + case OGS_TIMER_NF_INSTANCE_VALIDITY: + nf_instance = e->h.sbi.data; + ogs_assert(nf_instance); + ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); + + ogs_fsm_dispatch(&nf_instance->sm, e); + if (OGS_FSM_CHECK(&nf_instance->sm, ogs_sbi_nf_state_exception)) + ogs_error("State machine exception [%d]", e->h.timer_id); + break; + + case OGS_TIMER_SUBSCRIPTION_VALIDITY: + subscription_data = e->h.sbi.data; + ogs_assert(subscription_data); + + ogs_assert(true == + ogs_nnrf_nfm_send_nf_status_subscribe(subscription_data)); + + ogs_debug("Subscription validity expired [%s]", + subscription_data->id); + ogs_sbi_subscription_data_remove(subscription_data); + break; + + case OGS_TIMER_SBI_CLIENT_WAIT: + sbi_xact = e->h.sbi.data; + ogs_assert(sbi_xact); + + stream = sbi_xact->assoc_stream; + + ogs_sbi_xact_remove(sbi_xact); + + ogs_error("Cannot receive SBI message"); + if (stream) { + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_GATEWAY_TIMEOUT, NULL, + "Cannot receive SBI message", NULL)); + } + break; + + default: + ogs_error("Unknown timer[%s:%d]", + ogs_timer_get_name(e->h.timer_id), e->h.timer_id); + } + break; + + default: + ogs_error("No handler for event %s", msaf_event_get_name(e)); + break; + } + ogs_free(nf_name); +} + +/* vim:ts=8:sts=4:sw=4:expandtab: +*/ diff --git a/src/5gmsaf/msaf-mgmt-sm.h b/src/5gmsaf/msaf-mgmt-sm.h new file mode 100644 index 0000000..32fa42a --- /dev/null +++ b/src/5gmsaf/msaf-mgmt-sm.h @@ -0,0 +1,31 @@ +/* +License: 5G-MAG Public License (v1.0) +Copyright: (C) 2022 British Broadcasting Corporation + +For full license terms please see the LICENSE file distributed with this +program. If this file is missing then the license can be retrieved from +https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view + */ + +#ifndef MSAF_MGMT_SM_H +#define MSAF_MGMT_SM_H + +#include "event.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void msaf_mgmt_state_initial(ogs_fsm_t *s, msaf_event_t *e); +void msaf_mgmt_state_final(ogs_fsm_t *s, msaf_event_t *e); +void msaf_mgmt_state_functional(ogs_fsm_t *s, msaf_event_t *e); +void msaf_mgmt_state_exception(ogs_fsm_t *s, msaf_event_t *e); + +#define msaf_sm_debug(__pe) \ + ogs_debug("%s(): %s", __func__, msaf_event_get_name(__pe)) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/5gmsaf/msaf-sm.c b/src/5gmsaf/msaf-sm.c index 5b8491b..7eab9b0 100644 --- a/src/5gmsaf/msaf-sm.c +++ b/src/5gmsaf/msaf-sm.c @@ -394,6 +394,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *location; int m1_server_certificates_response_max_age; csr_cert = server_cert_new("newcsr", canonical_domain_name); + ogs_hash_set(msaf_provisioning_session->certificate_map, ogs_strdup(csr_cert->id), OGS_HASH_KEY_STRING, ogs_strdup(csr_cert->id)); ogs_sbi_response_t *response; location = ogs_msprintf("%s/%s", request->h.uri, csr_cert->id); if(csr_cert->cache_control_max_age){ @@ -431,9 +432,11 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { msaf_certificate_t *new_cert; int m1_server_certificates_response_max_age; - new_cert = server_cert_new("newcert", canonical_domain_name); ogs_sbi_response_t *response; char *location; + new_cert = server_cert_new("newcert", canonical_domain_name); + ogs_hash_set(msaf_provisioning_session->certificate_map, ogs_strdup(new_cert->id), OGS_HASH_KEY_STRING, ogs_strdup(new_cert->id)); + location = ogs_msprintf("%s/%s", request->h.uri, new_cert->id); if(new_cert->cache_control_max_age){ m1_server_certificates_response_max_age = new_cert->cache_control_max_age; @@ -511,10 +514,10 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) if (msaf_provisioning_session) { msaf_certificate_t *cert; ogs_sbi_response_t *response; - + const char *provisioning_session_cert; + provisioning_session_cert = ogs_hash_get(msaf_provisioning_session->certificate_map, message.h.resource.component[3], OGS_HASH_KEY_STRING); cert = server_cert_retrieve(message.h.resource.component[3]); - - if(!cert) { + if(!cert || !provisioning_session_cert) { ogs_error("unable to retrieve certificate [%s]", message.h.resource.component[3]); char *err = NULL; asprintf(&err,"Unable to retrieve Certificate not yet available"); @@ -737,24 +740,26 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); if(msaf_provisioning_session) { + const char *provisioning_session_cert; + provisioning_session_cert = ogs_hash_get(msaf_provisioning_session->certificate_map, message.h.resource.component[3], OGS_HASH_KEY_STRING); cert_id = message.h.resource.component[3]; cert = ogs_strdup(request->http.content); rv = server_cert_set(cert_id, cert); // response = ogs_sbi_response_new(); - if (rv == 0){ + if (rv == 0 && provisioning_session_cert){ response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_servercertificatesprovisioning_api, app_meta); nf_server_populate_response(response, 0, NULL, 204); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - } else if (rv == 3 ) { + } else if (rv == 3 && provisioning_session_cert ) { char *err = NULL; ogs_error("A server certificate with id [%s] already exist", cert_id); asprintf(&err,"A server certificate with id [%s] already exist", cert_id); ogs_assert(true == nf_server_send_error(stream, 403, 3, &message, "A server certificate already exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - } else if(rv == 4) { + } else if(rv == 4 || ! provisioning_session_cert) { char *err = NULL; ogs_error("Server certificate with id [%s] does not exist", cert_id); asprintf(&err,"Server certificate with id [%s] does not exist", cert_id); @@ -810,6 +815,8 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) nf_server_populate_response(response, 0, NULL, 204); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + msaf_provisioning_session_certificate_hash_remove(message.h.resource.component[1], message.h.resource.component[3]); + } else if (rv == 4 ) { char *err = NULL; asprintf(&err,"Certificate [%s] does not exist.", message.h.resource.component[3]); @@ -1024,6 +1031,66 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) END ogs_sbi_message_free(&message); break; + + CASE("5gmag-rt-management") + if (strcmp(message.h.api.version, "v1") != 0) { + char *error; + ogs_error("Not supported version [%s]", message.h.api.version); + + error = ogs_msprintf("Version [%s] not supported", message.h.api.version); + + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL, app_meta)); + + ogs_sbi_message_free(&message); + ogs_free(error); + break; + } + if(msaf_self()->config.mgmt_server_sockaddr || msaf_self()->config.mgmt_server_sockaddr_v6) { + char *error; + ogs_error("Cannot access the resource through this network, use the management network instead."); + error = ogs_msprintf("Cannot access the resource through this network, use the management network instead."); + ogs_assert(true == nf_server_send_error(stream, 403, 1, NULL, "Forbidden resource", error, NULL, NULL, app_meta)); + ogs_sbi_message_free(&message); + ogs_free(error); + break; + + } + SWITCH(message.h.resource.component[0]) + + CASE("provisioning-sessions") + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_GET) + char *provisioning_sessions = NULL; + ogs_sbi_response_t *response; + provisioning_sessions = enumerate_provisioning_sessions(); + if(provisioning_sessions) { + response = nf_server_new_response(NULL, "application/json", NULL, NULL, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, NULL, app_meta); + + nf_server_populate_response(response, strlen(provisioning_sessions), ogs_strdup(provisioning_sessions), 200); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + if (strcmp(provisioning_sessions,"[]")) ogs_free(provisioning_sessions); + break; + } else { + ogs_error("Internal Server Error."); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR, 0, &message, "Internal Server Error.", message.h.method, NULL, NULL, app_meta)); + } + DEFAULT + ogs_error("Invalid HTTP method [%s]", message.h.method); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 0, &message, "Invalid HTTP method.", message.h.method, NULL, NULL, app_meta)); + + END + break; + + DEFAULT + char *err; + ogs_error("Invalid resource name [%s]", message.h.resource.component[0]); + asprintf(&err,"Invalid resource name [%s]", message.h.resource.component[0]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid resource name", err, NULL, NULL, app_meta)); + + END + ogs_sbi_message_free(&message); + break; CASE("3gpp-m5") if (strcmp(message.h.api.version, "v2") != 0) { diff --git a/src/5gmsaf/provisioning-session.c b/src/5gmsaf/provisioning-session.c index f28d081..94001c9 100644 --- a/src/5gmsaf/provisioning-session.c +++ b/src/5gmsaf/provisioning-session.c @@ -21,10 +21,16 @@ typedef struct free_ogs_hash_provisioning_session_s { ogs_hash_t *hash; } free_ogs_hash_provisioning_session_t; +typedef struct free_ogs_hash_provisioning_session_certificate_s { + char *certificate; + ogs_hash_t *hash; +} free_ogs_hash_provisioning_session_certificate_t; + static regex_t *relative_path_re = NULL; static int ogs_hash_do_cert_check(void *rec, const void *key, int klen, const void *value); static int free_ogs_hash_provisioning_session(void *rec, const void *key, int klen, const void *value); +static int free_ogs_hash_provisioning_session_certificate(void *rec, const void *key, int klen, const void *value); static char* url_path_create(const char* macro, const char* session_id, const msaf_application_server_node_t *msaf_as); static void tidy_relative_path_re(void); static const char *calculate_provisioning_session_hash(OpenAPI_provisioning_session_t *provisioning_session); @@ -457,6 +463,19 @@ msaf_provisioning_session_hash_remove(char *provisioning_session_id) ogs_hash_do(free_ogs_hash_provisioning_session, &fohps, msaf_self()->provisioningSessions_map); } +void +msaf_provisioning_session_certificate_hash_remove(char *provisioning_session_id, char *certificate_id) +{ + msaf_provisioning_session_t *provisioning_session = NULL; + provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(provisioning_session_id); + + free_ogs_hash_provisioning_session_certificate_t fohpsc = { + certificate_id, + provisioning_session->certificate_map + }; + ogs_hash_do(free_ogs_hash_provisioning_session_certificate, &fohpsc, provisioning_session->certificate_map); +} + int uri_relative_check(char *entry_point_path) { int result; @@ -499,8 +518,35 @@ int uri_relative_check(char *entry_point_path) } } +char *enumerate_provisioning_sessions(void) +{ + ogs_hash_index_t *hi, *next_hi; + char *provisioning_sessions = "[]"; + int number_of_provisioning_sessions = ogs_hash_count(msaf_self()->provisioningSessions_map); + if (number_of_provisioning_sessions) + { + provisioning_sessions = ogs_calloc(1, (4 + (sizeof(char)*(OGS_UUID_FORMATTED_LENGTH + 1) *number_of_provisioning_sessions) +1)); + provisioning_sessions[0] = '['; + + for (hi = ogs_hash_first(msaf_self()->provisioningSessions_map); hi; hi = ogs_hash_next(hi)) { + const char *key = NULL; + const char *val = NULL; + char *provisioning_session = NULL; + key = ogs_hash_this_key(hi); + ogs_assert(key); + val = ogs_hash_this_val(hi); + ogs_assert(val); + provisioning_session = ogs_msprintf("\"%s\", ", key); + strcat(provisioning_sessions, provisioning_session); + ogs_free(provisioning_session); + + } + provisioning_sessions[strlen(provisioning_sessions) - 2] = ']'; + provisioning_sessions[strlen(provisioning_sessions) - 1] = '\0'; + } + return provisioning_sessions; -/***** Private functions *****/ +} static const char *calculate_provisioning_session_hash(OpenAPI_provisioning_session_t *provisioning_session) { @@ -548,6 +594,19 @@ free_ogs_hash_provisioning_session(void *rec, const void *key, int klen, const v return 1; } +static int +free_ogs_hash_provisioning_session_certificate(void *rec, const void *key, int klen, const void *value) +{ + free_ogs_hash_provisioning_session_certificate_t *fohpsc = (free_ogs_hash_provisioning_session_certificate_t *)rec; + if (!strcmp(fohpsc->certificate, (char *)key)) { + + ogs_hash_set(fohpsc->hash, key, klen, NULL); + ogs_free((void*)key); + + } + return 1; +} + static char* url_path_create(const char* macro, const char* session_id, const msaf_application_server_node_t *msaf_as) { diff --git a/src/5gmsaf/provisioning-session.h b/src/5gmsaf/provisioning-session.h index d00a2f9..93b47b0 100644 --- a/src/5gmsaf/provisioning-session.h +++ b/src/5gmsaf/provisioning-session.h @@ -62,6 +62,8 @@ extern void msaf_delete_certificate(char *resource_id); extern void msaf_provisioning_session_hash_remove(char *provisioning_session_id); +extern void msaf_provisioning_session_certificate_hash_remove(char *provisioning_session_id, char *certificate_id); + extern int uri_relative_check(char *entry_point_path); extern int @@ -69,6 +71,8 @@ msaf_distribution_create(cJSON *content_hosting_config, msaf_provisioning_sessio extern cJSON *msaf_get_content_hosting_configuration_by_provisioning_session_id(char *provisioning_session_id); +extern char *enumerate_provisioning_sessions(void); + #ifdef __cplusplus } #endif diff --git a/src/5gmsaf/sbi-path.c b/src/5gmsaf/sbi-path.c index 2c9ad9f..14e41dc 100644 --- a/src/5gmsaf/sbi-path.c +++ b/src/5gmsaf/sbi-path.c @@ -59,4 +59,4 @@ void msaf_sbi_close(void) { ogs_sbi_client_stop_all(); ogs_sbi_server_stop_all(); -} +} \ No newline at end of file From 867f47a0674af86b123df74f035cef9951a6e3ee Mon Sep 17 00:00:00 2001 From: deva Date: Mon, 6 Mar 2023 08:24:47 +0000 Subject: [PATCH 17/48] Introduce seperate state management for the M1 Management Interface --- src/5gmsaf/af-sm-msaf.c | 269 ---------------------------------------- 1 file changed, 269 deletions(-) delete mode 100644 src/5gmsaf/af-sm-msaf.c diff --git a/src/5gmsaf/af-sm-msaf.c b/src/5gmsaf/af-sm-msaf.c deleted file mode 100644 index 6aced82..0000000 --- a/src/5gmsaf/af-sm-msaf.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * License: 5G-MAG Public License (v1.0) - * Copyright: (C) 2022 British Broadcasting Corporation - * - * For full license terms please see the LICENSE file distributed with this - * program. If this file is missing then the license can be retrieved from - * https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view - */ - - -#include "ogs-sbi.h" -#include "sbi-path.h" -#include "context.h" -#include "server.h" - - -void af_state_initial(ogs_fsm_t *s, msaf_event_t *e) -{ - msaf_sm_debug(e); - - ogs_assert(s); - - OGS_FSM_TRAN(s, &af_state_functional); -} - -void af_state_final(ogs_fsm_t *s, af_event_t *e) -{ - af_sm_debug(e); - - ogs_assert(s); -} - -void af_state_functional(ogs_fsm_t *s, af_event_t *e) -{ - int rv; - - ogs_sbi_stream_t *stream = NULL; - ogs_sbi_request_t *request = NULL; - - ogs_sbi_nf_instance_t *nf_instance = NULL; - ogs_sbi_subscription_data_t *subscription_data = NULL; - ogs_sbi_response_t *response = NULL; - ogs_sbi_message_t message; - ogs_sbi_xact_t *sbi_xact = NULL; - - af_sm_debug(e); - - ogs_assert(s); - - msaf_context_server_name_set(); - - switch (e->h.id) { - case OGS_FSM_ENTRY_SIG: - ogs_info("[%s] AF Running", ogs_sbi_self()->nf_instance->id); - - break; - - case OGS_FSM_EXIT_SIG: - break; - - case OGS_EVENT_SBI_SERVER: - request = e->h.sbi.request; - ogs_assert(request); - stream = e->h.sbi.data; - ogs_assert(stream); - - ogs_info("AF SM"); - - rv = ogs_sbi_parse_header(&message, &request->h); - if (rv != OGS_OK) { - ogs_error("ogs_sbi_parse_header() failed"); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "cannot parse HTTP message", NULL, NULL, NULL, app_meta)); - - break; - } - - SWITCH(message.h.service.name) - CASE(OGS_SBI_SERVICE_NAME_NNRF_NFM) - if (strcmp(message.h.api.version, OGS_SBI_API_V1) != 0) { - ogs_error("Not supported version [%s]", message.h.api.version); - ogs_assert(true == ogs_sbi_server_send_error( - stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, - &message, "Not supported version", NULL)); - ogs_sbi_message_free(&message); - break; - } - SWITCH(message.h.resource.component[0]) - CASE(OGS_SBI_RESOURCE_NAME_NF_STATUS_NOTIFY) - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_POST) - ogs_nnrf_nfm_handle_nf_status_notify(stream, &message); - break; - - DEFAULT - ogs_error("Invalid HTTP method [%s]", message.h.method); - ogs_assert(true == - ogs_sbi_server_send_error(stream, - OGS_SBI_HTTP_STATUS_FORBIDDEN, &message, - "Invalid HTTP method", message.h.method)); - END - break; - - DEFAULT - ogs_error("Invalid resource name [%s]", - message.h.resource.component[0]); - ogs_assert(true == - ogs_sbi_server_send_error(stream, - OGS_SBI_HTTP_STATUS_BAD_REQUEST, &message, - "Invalid resource name", - message.h.resource.component[0])); - END - ogs_sbi_message_free(&message); - break; - - DEFAULT - ogs_error("Invalid API name [%s]", message.h.service.name); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid API name.", message.h.service.name, NULL, NULL, app_meta)); - - END - break; - - case OGS_EVENT_SBI_CLIENT: - ogs_assert(e); - - response = e->h.sbi.response; - ogs_assert(response); - rv = ogs_sbi_parse_header(&message, &response->h); - if (rv != OGS_OK) { - ogs_error("ogs_sbi_parse_header() failed"); - ogs_sbi_message_free(&message); - ogs_sbi_response_free(response); - break; - } - { - ogs_hash_index_t *hi; - for (hi = ogs_hash_first(response->http.headers); - hi; hi = ogs_hash_next(hi)) { - if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { - message.http.content_type = ogs_hash_this_val(hi); - } else if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_LOCATION)) { - message.http.location = ogs_hash_this_val(hi); - } - } - } - - message.res_status = response->status; - - SWITCH(message.h.service.name) - - CASE(OGS_SBI_SERVICE_NAME_NNRF_NFM) - - SWITCH(message.h.resource.component[0]) - CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES) - nf_instance = e->h.sbi.data; - ogs_assert(nf_instance); - ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); - - e->h.sbi.message = &message; - ogs_fsm_dispatch(&nf_instance->sm, e); - break; - - CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS) - subscription_data = e->h.sbi.data; - ogs_assert(subscription_data); - - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_POST) - if (message.res_status == OGS_SBI_HTTP_STATUS_CREATED || - message.res_status == OGS_SBI_HTTP_STATUS_OK) { - ogs_nnrf_nfm_handle_nf_status_subscribe( - subscription_data, &message); - } else { - ogs_error("HTTP response error : %d", - message.res_status); - } - break; - - CASE(OGS_SBI_HTTP_METHOD_DELETE) - if (message.res_status == OGS_SBI_HTTP_STATUS_NO_CONTENT) { - ogs_sbi_subscription_data_remove(subscription_data); - } else { - ogs_error("HTTP response error : %d", - message.res_status); - } - break; - - DEFAULT - ogs_error("Invalid HTTP method [%s]", message.h.method); - ogs_assert_if_reached(); - END - break; - - DEFAULT - ogs_error("Invalid resource name [%s]", - message.h.resource.component[0]); - ogs_assert_if_reached(); - END - break; - - DEFAULT - ogs_error("Invalid service name [%s]", message.h.service.name); - ogs_assert_if_reached(); - END - - ogs_sbi_message_free(&message); - ogs_sbi_response_free(response); - break; - - case OGS_EVENT_SBI_TIMER: - ogs_assert(e); - - switch(e->h.timer_id) { - case OGS_TIMER_NF_INSTANCE_REGISTRATION_INTERVAL: - case OGS_TIMER_NF_INSTANCE_HEARTBEAT_INTERVAL: - case OGS_TIMER_NF_INSTANCE_NO_HEARTBEAT: - case OGS_TIMER_NF_INSTANCE_VALIDITY: - nf_instance = e->h.sbi.data; - ogs_assert(nf_instance); - ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); - - ogs_fsm_dispatch(&nf_instance->sm, e); - if (OGS_FSM_CHECK(&nf_instance->sm, ogs_sbi_nf_state_exception)) - ogs_error("State machine exception [%d]", e->h.timer_id); - break; - - case OGS_TIMER_SUBSCRIPTION_VALIDITY: - subscription_data = e->h.sbi.data; - ogs_assert(subscription_data); - - ogs_assert(true == - ogs_nnrf_nfm_send_nf_status_subscribe(subscription_data)); - - ogs_debug("Subscription validity expired [%s]", - subscription_data->id); - ogs_sbi_subscription_data_remove(subscription_data); - break; - - case OGS_TIMER_SBI_CLIENT_WAIT: - sbi_xact = e->h.sbi.data; - ogs_assert(sbi_xact); - - stream = sbi_xact->assoc_stream; - - ogs_sbi_xact_remove(sbi_xact); - - ogs_error("Cannot receive SBI message"); - if (stream) { - ogs_assert(true == - ogs_sbi_server_send_error(stream, - OGS_SBI_HTTP_STATUS_GATEWAY_TIMEOUT, NULL, - "Cannot receive SBI message", NULL)); - } - break; - - default: - ogs_error("Unknown timer[%s:%d]", - ogs_timer_get_name(e->h.timer_id), e->h.timer_id); - } - break; - - default: - ogs_error("No handler for event %s", msaf_event_get_name(e)); - break; - } - ogs_free(nf_name); -} - -/* vim:ts=8:sts=4:sw=4:expandtab: -*/ From 5916386a686f4329695db65c2a41e6342afb77b4 Mon Sep 17 00:00:00 2001 From: David Waring Date: Mon, 6 Mar 2023 17:17:26 +0000 Subject: [PATCH 18/48] Fix issues found during testing. --- src/5gmsaf/application-server-context.c | 29 ++++++---- src/5gmsaf/application-server-context.h | 4 +- src/5gmsaf/certmgr.c | 74 ++++++++++++++++++++++--- src/5gmsaf/certmgr.h | 1 + src/5gmsaf/event.c | 47 ++++++++-------- src/5gmsaf/init.c | 4 +- src/5gmsaf/msaf-mgmt-sm.c | 3 +- src/5gmsaf/msaf-sm.c | 41 ++++++++------ 8 files changed, 138 insertions(+), 65 deletions(-) diff --git a/src/5gmsaf/application-server-context.c b/src/5gmsaf/application-server-context.c index 75e2ebe..f185bc0 100644 --- a/src/5gmsaf/application-server-context.c +++ b/src/5gmsaf/application-server-context.c @@ -8,10 +8,12 @@ program. If this file is missing then the license can be retrieved from https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view */ -#include "application-server-context.h" +#include "certmgr.h" #include "context.h" #include "utilities.h" +#include "application-server-context.h" + typedef struct client_request_info { msaf_application_server_state_node_t *as_state; purge_resource_id_node_t *purge_node; @@ -28,7 +30,7 @@ static void msaf_application_server_remove(msaf_application_server_node_t *msaf_ /***** Public functions *****/ -void +int msaf_application_server_state_set_on_post( msaf_provisioning_session_t *provisioning_session) { msaf_application_server_node_t *msaf_as; @@ -49,7 +51,10 @@ msaf_application_server_state_set_on_post( msaf_provisioning_session_t *provisio ogs_list_add(&as_state->upload_certificates, node); } ogs_free(certs); + } else { + return 0; } + chc = ogs_calloc(1, sizeof(resource_id_node_t)); ogs_assert(chc); chc->state = ogs_strdup(provisioning_session->provisioningSessionId); @@ -66,6 +71,7 @@ msaf_application_server_state_set_on_post( msaf_provisioning_session_t *provisio next_action_for_application_server(as_state); } } + return 1; } void @@ -91,7 +97,7 @@ msaf_application_server_state_update( msaf_provisioning_session_t *provisioning_ } } -void +int msaf_application_server_state_set(msaf_application_server_state_node_t *as_state, msaf_provisioning_session_t *provisioning_session) { resource_id_node_t *chc; @@ -105,6 +111,8 @@ msaf_application_server_state_set(msaf_application_server_state_node_t *as_state ogs_list_add(&as_state->upload_certificates, node); } ogs_free(certs); + } else { + return 0; } chc = ogs_calloc(1, sizeof(resource_id_node_t)); @@ -118,6 +126,8 @@ msaf_application_server_state_set(msaf_application_server_state_node_t *as_state ogs_list_add(&as_state->assigned_provisioning_sessions, assigned_provisioning_sessions); next_action_for_application_server(as_state); + + return 1; } msaf_application_server_node_t * @@ -160,13 +170,12 @@ void next_action_for_application_server(msaf_application_server_state_node_t *as } else if (as_state->current_content_hosting_configurations == NULL) { m3_client_as_state_requests(as_state, NULL, NULL, NULL, (char *)OGS_SBI_HTTP_METHOD_GET, "content-hosting-configurations"); } else if (ogs_list_first(&as_state->upload_certificates) != NULL) { - const char *upload_cert_filename; char *upload_cert_id; char *provisioning_session; char *cert_id; - char *data; char *component; resource_id_node_t *cert_id_node; + msaf_certificate_t *certificate; resource_id_node_t *upload_cert = ogs_list_first(&as_state->upload_certificates); ogs_list_for_each(as_state->current_certificates, cert_id_node) { @@ -176,19 +185,17 @@ void next_action_for_application_server(msaf_application_server_state_node_t *as } upload_cert_id = ogs_strdup(upload_cert->state); provisioning_session = strtok_r(upload_cert_id,":",&cert_id); - upload_cert_filename = msaf_get_certificate_filename(provisioning_session, cert_id); - data = read_file(upload_cert_filename); + certificate = server_cert_get_servercert(cert_id); component = ogs_msprintf("certificates/%s:%s", provisioning_session, cert_id); if (cert_id_node) { ogs_debug("M3 client: Sending PUT method to Application Server [%s] for Certificate: [%s]", as_state->application_server->canonicalHostname, upload_cert->state); - m3_client_as_state_requests(as_state, NULL, "application/x-pem-file", data, (char *)OGS_SBI_HTTP_METHOD_PUT, component); - free(data); + m3_client_as_state_requests(as_state, NULL, "application/x-pem-file", certificate->certificate, (char *)OGS_SBI_HTTP_METHOD_PUT, component); } else { ogs_debug("M3 client: Sending POST method to Application Server [%s]for Certificate: [%s]", as_state->application_server->canonicalHostname, upload_cert->state); - m3_client_as_state_requests(as_state, NULL, "application/x-pem-file", data, (char *)OGS_SBI_HTTP_METHOD_POST, component); - free(data); + m3_client_as_state_requests(as_state, NULL, "application/x-pem-file", certificate->certificate, (char *)OGS_SBI_HTTP_METHOD_POST, component); } + msaf_certificate_free(certificate); ogs_free(component); ogs_free(upload_cert_id); diff --git a/src/5gmsaf/application-server-context.h b/src/5gmsaf/application-server-context.h index 38a9a38..d4d4377 100644 --- a/src/5gmsaf/application-server-context.h +++ b/src/5gmsaf/application-server-context.h @@ -70,13 +70,13 @@ typedef struct purge_resource_id_node_s { * @param as_state The application server state to add this CHC to. * @param provisioning_session The provisioning session of the CHC. */ -extern void msaf_application_server_state_set(msaf_application_server_state_node_t *as_state, msaf_provisioning_session_t *provisioning_session); +extern int msaf_application_server_state_set(msaf_application_server_state_node_t *as_state, msaf_provisioning_session_t *provisioning_session); extern void msaf_application_server_state_log(ogs_list_t *list, const char* list_name); extern msaf_application_server_node_t *msaf_application_server_add(char *canonical_hostname, char *url_path_prefix_format, int m3_port); extern void msaf_application_server_remove_all(void); extern void msaf_application_server_print_all(void); extern void next_action_for_application_server(msaf_application_server_state_node_t *as_state); -extern void msaf_application_server_state_set_on_post( msaf_provisioning_session_t *provisioning_session); +extern int msaf_application_server_state_set_on_post( msaf_provisioning_session_t *provisioning_session); extern void msaf_application_server_state_update( msaf_provisioning_session_t *provisioning_session); diff --git a/src/5gmsaf/certmgr.c b/src/5gmsaf/certmgr.c index e1f2769..a082d34 100644 --- a/src/5gmsaf/certmgr.c +++ b/src/5gmsaf/certmgr.c @@ -16,9 +16,6 @@ #define MAX_CHILD_PROCESS 16 -static ogs_proc_t process[MAX_CHILD_PROCESS]; -static int process_num = 0; - static msaf_certificate_t *msaf_certificate_populate(const char *certid, const char *cert, int out_return_code); int server_cert_delete(const char *certid) @@ -35,7 +32,7 @@ int server_cert_delete(const char *certid) commandLine[3] = certid; commandLine[4] = NULL; - current = &process[process_num++]; + current = (ogs_proc_t*)ogs_calloc(1, sizeof(*current)); ret = ogs_proc_create(commandLine, ogs_proc_option_combined_stdout_stderr| ogs_proc_option_inherit_environment, @@ -52,6 +49,8 @@ int server_cert_delete(const char *certid) ret = ogs_proc_destroy(current); ogs_assert(ret == 0); + ogs_free(current); + return out_return_code; } @@ -73,7 +72,7 @@ msaf_certificate_t *server_cert_retrieve(const char *certid) commandLine[3] = certid; commandLine[4] = NULL; - current = &process[process_num++]; + current = (ogs_proc_t*)ogs_calloc(1, sizeof(*current)); ret = ogs_proc_create(commandLine, ogs_proc_option_combined_stdout_stderr| ogs_proc_option_inherit_environment, @@ -97,10 +96,65 @@ msaf_certificate_t *server_cert_retrieve(const char *certid) ogs_assert(ret == 0); ret = ogs_proc_destroy(current); ogs_assert(ret == 0); + ogs_free(current); + if(!out_return_code){ msaf_certificate = msaf_certificate_populate(certid, cert, out_return_code); ogs_assert(msaf_certificate); } + ogs_free(cert); + return msaf_certificate; +} + +msaf_certificate_t *server_cert_get_servercert(const char *certid) +{ + const char *commandLine[OGS_ARG_MAX]; + ogs_proc_t *current = NULL; + FILE *out = NULL; + char buf[OGS_HUGE_LEN]; + char *cert = NULL; + int ret = 0, out_return_code = 0; + msaf_certificate_t *msaf_certificate = NULL; + size_t cert_size = 0; + size_t cert_reserved = 0; + + commandLine[0] = msaf_self()->config.certificateManager; + commandLine[1] = "-c"; + commandLine[2] = "servercert"; + commandLine[3] = certid; + commandLine[4] = NULL; + + current = (ogs_proc_t*)ogs_calloc(1, sizeof(*current)); + ret = ogs_proc_create(commandLine, + ogs_proc_option_combined_stdout_stderr| + ogs_proc_option_inherit_environment, + current); + ogs_assert(ret == 0); + out = ogs_proc_stdout(current); + ogs_assert(out); + + cert = ogs_calloc(1, 4096); + cert_reserved = 4096; + + while(fgets(buf, OGS_HUGE_LEN, out)) { + cert_size += strlen (buf); + if(cert_size > cert_reserved - 1) { + cert_reserved +=4096; + cert = ogs_realloc(cert,cert_reserved); + } + strcat(cert,buf); + } + ret = ogs_proc_join(current, &out_return_code); + ogs_assert(ret == 0); + ret = ogs_proc_destroy(current); + ogs_assert(ret == 0); + ogs_free(current); + + if(!out_return_code){ + msaf_certificate = msaf_certificate_populate(certid, cert, out_return_code); + ogs_assert(msaf_certificate); + } + ogs_free(cert); return msaf_certificate; } @@ -117,7 +171,7 @@ int server_cert_set(const char *cert_id, const char *cert) commandLine[3] = cert_id; commandLine[4] = NULL; - current = &process[process_num++]; + current = (ogs_proc_t*)ogs_calloc(1, sizeof(*current)); ret = ogs_proc_create(commandLine, ogs_proc_option_inherit_environment, current); @@ -134,6 +188,8 @@ int server_cert_set(const char *cert_id, const char *cert) ogs_assert(ret == 0); ret = ogs_proc_destroy(current); ogs_assert(ret == 0); + ogs_free(current); + return out_return_code; } @@ -167,7 +223,7 @@ msaf_certificate_t *server_cert_new(const char *operation, const char *operation commandLine[4] = canonical_domain_name; commandLine[5] = NULL; - current = &process[process_num++]; + current = (ogs_proc_t*)ogs_calloc(1, sizeof(*current)); ret = ogs_proc_create(commandLine, ogs_proc_option_combined_stdout_stderr| ogs_proc_option_inherit_environment, @@ -191,6 +247,7 @@ msaf_certificate_t *server_cert_new(const char *operation, const char *operation ogs_assert(ret == 0); ret = ogs_proc_destroy(current); ogs_assert(ret == 0); + ogs_free(current); msaf_certificate = msaf_certificate_populate(id, cert, out_return_code); ogs_assert(msaf_certificate); ogs_free(cert); @@ -212,7 +269,7 @@ char *check_in_cert_list(const char *canonical_domain_name) commandLine[2] = "list"; commandLine[3] = NULL; - current = &process[process_num++]; + current = (ogs_proc_t*)ogs_calloc(1, sizeof(*current)); ret = ogs_proc_create(commandLine, ogs_proc_option_combined_stdout_stderr| ogs_proc_option_inherit_environment, @@ -235,6 +292,7 @@ char *check_in_cert_list(const char *canonical_domain_name) ogs_assert(ret == 0); ret = ogs_proc_destroy(current); ogs_assert(ret == 0); + ogs_free(current); if (!certificate) return NULL; diff --git a/src/5gmsaf/certmgr.h b/src/5gmsaf/certmgr.h index 6ff9a2a..0317049 100644 --- a/src/5gmsaf/certmgr.h +++ b/src/5gmsaf/certmgr.h @@ -36,6 +36,7 @@ typedef struct msaf_assigned_certificate_s { extern msaf_certificate_t *server_cert_new(const char *operation, const char *operation_params); extern int server_cert_set(const char *cert_id, const char *cert); extern msaf_certificate_t *server_cert_retrieve(const char *certid); +extern msaf_certificate_t *server_cert_get_servercert(const char *certid); extern char *check_in_cert_list(const char *canonical_domain_name); extern int server_cert_delete(const char *certid); extern void msaf_certificate_free(msaf_certificate_t *cert); diff --git a/src/5gmsaf/event.c b/src/5gmsaf/event.c index bc9575b..31cc502 100644 --- a/src/5gmsaf/event.c +++ b/src/5gmsaf/event.c @@ -30,37 +30,38 @@ const char *msaf_event_get_name(msaf_event_t *e) int get_server_type_from_event(msaf_event_t *e) { - ogs_sbi_stream_t *stream = NULL; - ogs_sbi_server_t *server = NULL; + ogs_sbi_stream_t *stream = e->h.sbi.data; - stream = e->h.sbi.data; - ogs_assert(stream); + if (stream) { + ogs_sbi_server_t *server; - server = ogs_sbi_server_from_stream(stream); - ogs_assert(server); + server = ogs_sbi_server_from_stream(stream); + ogs_assert(server); - if (ogs_sockaddr_is_equal(server->node.addr, msaf_self()->config.app_server_sockaddr) == true) { - ogs_info("returns MSAF_APP_SERVER"); - return MSAF_APP_SERVER; - } + if (ogs_sockaddr_is_equal(server->node.addr, msaf_self()->config.app_server_sockaddr) == true) { + ogs_info("returns MSAF_APP_SERVER"); + return MSAF_APP_SERVER; + } - if (ogs_sockaddr_is_equal(server->node.addr, msaf_self()->config.mgmt_server_sockaddr) == true) { - ogs_info("returns MSAF_MGMT_SERVER"); - return MSAF_MGMT_SERVER; - } - - if (ogs_sockaddr_is_equal(server->node.addr, msaf_self()->config.app_server_sockaddr_v6) == true) { - ogs_info("returns MSAF_APP_SERVER"); - return MSAF_APP_SERVER; - } + if (ogs_sockaddr_is_equal(server->node.addr, msaf_self()->config.mgmt_server_sockaddr) == true) { + ogs_info("returns MSAF_MGMT_SERVER"); + return MSAF_MGMT_SERVER; + } - if (ogs_sockaddr_is_equal(server->node.addr, msaf_self()->config.mgmt_server_sockaddr_v6) == true) { - ogs_info("returns MSAF_MGMT_SERVER"); - return MSAF_MGMT_SERVER; + if (ogs_sockaddr_is_equal(server->node.addr, msaf_self()->config.app_server_sockaddr_v6) == true) { + ogs_info("returns MSAF_APP_SERVER"); + return MSAF_APP_SERVER; + } - } + if (ogs_sockaddr_is_equal(server->node.addr, msaf_self()->config.mgmt_server_sockaddr_v6) == true) { + ogs_info("returns MSAF_MGMT_SERVER"); + return MSAF_MGMT_SERVER; + } + } return MSAF_APP_SERVER; } +/* vim:ts=8:sts=4:sw=4:expandtab: +*/ diff --git a/src/5gmsaf/init.c b/src/5gmsaf/init.c index 180f491..da8a8e6 100644 --- a/src/5gmsaf/init.c +++ b/src/5gmsaf/init.c @@ -99,9 +99,7 @@ static void msaf_main(void *data) int rv; ogs_fsm_init(&msaf_sm, msaf_state_initial, msaf_state_final, 0); - if(msaf_self()->config.mgmt_server_sockaddr || msaf_self()->config.mgmt_server_sockaddr_v6) { - ogs_fsm_init(&msaf_mgmt_sm, msaf_mgmt_state_initial, msaf_mgmt_state_final, 0); - } + ogs_fsm_init(&msaf_mgmt_sm, msaf_mgmt_state_initial, msaf_mgmt_state_final, 0); for ( ;; ) { ogs_pollset_poll(ogs_app()->pollset, diff --git a/src/5gmsaf/msaf-mgmt-sm.c b/src/5gmsaf/msaf-mgmt-sm.c index b8905a4..9bb553d 100644 --- a/src/5gmsaf/msaf-mgmt-sm.c +++ b/src/5gmsaf/msaf-mgmt-sm.c @@ -57,7 +57,6 @@ void msaf_mgmt_state_functional(ogs_fsm_t *s, msaf_event_t *e) msaf_context_server_name_set(); char *nf_name = ogs_msprintf("5GMSdAF-%s", msaf_self()->server_name); const nf_server_app_metadata_t app_metadata = { MSAF_NAME, MSAF_VERSION, nf_name}; - const nf_server_interface_metadata_t *m1_provisioningsession_api = &m1_mgmt_provisioningsession_api_metadata; const nf_server_app_metadata_t *app_meta = &app_metadata; ogs_assert(s); @@ -145,7 +144,7 @@ void msaf_mgmt_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_sbi_response_t *response; provisioning_sessions = enumerate_provisioning_sessions(); if (provisioning_sessions) { - response = nf_server_new_response(NULL, "application/json", NULL, NULL, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, NULL, app_meta); + response = nf_server_new_response(NULL, "application/json", 0, NULL, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, NULL, app_meta); nf_server_populate_response(response, strlen(provisioning_sessions), ogs_strdup(provisioning_sessions), 200); ogs_assert(response); diff --git a/src/5gmsaf/msaf-sm.c b/src/5gmsaf/msaf-sm.c index 7eab9b0..198181a 100644 --- a/src/5gmsaf/msaf-sm.c +++ b/src/5gmsaf/msaf-sm.c @@ -330,23 +330,29 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) if(rv){ ogs_debug("Content Hosting Configuration created successfully"); - msaf_application_server_state_set_on_post(msaf_provisioning_session); - chc = msaf_get_content_hosting_configuration_by_provisioning_session_id(message.h.resource.component[1]); - if (chc != NULL) { - char *text; - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, NULL, m1_contentprotocolsdiscovery_api, app_meta); - text = cJSON_Print(chc); - nf_server_populate_response(response, strlen(text), text, 201); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - cJSON_Delete(chc); - cJSON_Delete(content_hosting_config); + if (msaf_application_server_state_set_on_post(msaf_provisioning_session)) { + chc = msaf_get_content_hosting_configuration_by_provisioning_session_id(message.h.resource.component[1]); + if (chc != NULL) { + char *text; + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, NULL, m1_contentprotocolsdiscovery_api, app_meta); + text = cJSON_Print(chc); + nf_server_populate_response(response, strlen(text), text, 201); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + cJSON_Delete(chc); + cJSON_Delete(content_hosting_config); + } else { + char *err = NULL; + ogs_error("Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); + asprintf(&err,"Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + } } else { char *err = NULL; - ogs_error("Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); - asprintf(&err,"Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + ogs_error("Verification error on Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); + asprintf(&err,"Verification error on Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 400, 2, &message, "Bad Content Hosting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } } else { char *err = NULL; @@ -423,6 +429,9 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) if (cert != NULL) { ogs_sbi_response_t *response; char *location; + + ogs_hash_set(msaf_provisioning_session->certificate_map, ogs_strdup(cert), OGS_HASH_KEY_STRING, ogs_strdup(cert)); + location = ogs_msprintf("%s/%s", request->h.uri, cert); response = nf_server_new_response(location, NULL, 0, NULL, 0, NULL, m1_servercertificatesprovisioning_api, app_meta); nf_server_populate_response(response, 0, NULL, 200); @@ -1064,7 +1073,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_sbi_response_t *response; provisioning_sessions = enumerate_provisioning_sessions(); if(provisioning_sessions) { - response = nf_server_new_response(NULL, "application/json", NULL, NULL, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, NULL, app_meta); + response = nf_server_new_response(NULL, "application/json", 0, NULL, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, NULL, app_meta); nf_server_populate_response(response, strlen(provisioning_sessions), ogs_strdup(provisioning_sessions), 200); ogs_assert(response); From 110c9648e835dc59b9ca8effff09f1bedecbd365 Mon Sep 17 00:00:00 2001 From: David Waring Date: Mon, 6 Mar 2023 17:17:52 +0000 Subject: [PATCH 19/48] Add M1Session class and script to use it. --- tools/python3/lib/rt_m1_client/data_store.py | 79 ++++++++ tools/python3/lib/rt_m1_client/session.py | 187 +++++++++++++++++++ tools/python3/m1_session_cli.py | 72 +++++++ 3 files changed, 338 insertions(+) create mode 100644 tools/python3/lib/rt_m1_client/data_store.py create mode 100644 tools/python3/lib/rt_m1_client/session.py create mode 100755 tools/python3/m1_session_cli.py diff --git a/tools/python3/lib/rt_m1_client/data_store.py b/tools/python3/lib/rt_m1_client/data_store.py new file mode 100644 index 0000000..4b0bcac --- /dev/null +++ b/tools/python3/lib/rt_m1_client/data_store.py @@ -0,0 +1,79 @@ +#!/usr/bin/python3 +#============================================================================== +# 5G-MAG Reference Tools: M1 Session Persistent Data Store +#============================================================================== +# +# File: rt_m1_client/data_store.py +# License: 5G-MAG Public License (v1.0) +# Author: David Waring +# Copyright: (C) 2022 British Broadcasting Corporation +# +# For full license terms please see the LICENSE file distributed with this +# program. If this file is missing then the license can be retrieved from +# https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +# +#============================================================================== +# +# M1 Session DataStore classes +# ============================ +# +# This module contains classes to implement a persistent data store for use by +# the M1Session class. +# +# There are 2 classes DataStore is the base class and JSONFileDataStore is an +# implementation which stores the persistent data objects as JSON objects. +# +'''5G-MAG Reference Tools: M1 Session DataStore classes +==================================================== + +The DataStore class provides a base class for storing persistent data using +a key string. This data can then be retrieved later so that the application can carry on where it left off. + +The JSONFileDataStore class is an implementation that stores the data being +represented in JSON notation as a set of files. +''' +import json +import logging +from typing import Any + +class DataStore: + '''DataStore base class + ''' + def get(self, key: str, default: Any = None) -> Any: + '''Get a persisted value by key name + ''' + raise NotImplementedError('DataStore implementation should override this method') + + def set(self, key: str, value: Any) -> bool: + '''Store a persisted value using the key name + ''' + raise NotImplementedError('DataStore implementation should override this method') + +class JSONFileDataStore(DataStore): + '''JSONFileDataStore class + + This class implements a DataStore as a set of files containing JSON. + ''' + def __init__(self, data_store_dir: str): + self.__dir = data_store_dir + if not os.path.exists(self.__dir): + os.makedirs(self.__dir) + if not os.path.is_dir(self.__dir): + raise RuntimeError(f'{self.__dir} is not a directory') + + def get(self, key: str, default: Any = None) -> Any: + '''Get a persisted value by key name + ''' + json_file = os.path.join(self.__dir, f'{key}.json') + if not os.path.exists(json_file) or not os.path.is_file(json_file): + return default + val = json.load(json_file) + return val + + def set(self, key: str, value: Any) -> bool: + '''Store a persisted value using the key name + ''' + json_file = os.path.join(self.__dir, f'{key}.json') + with open(json_file, 'w') as json_out: + json_out.write(json.dumps(value)) + return True diff --git a/tools/python3/lib/rt_m1_client/session.py b/tools/python3/lib/rt_m1_client/session.py new file mode 100644 index 0000000..3f70d42 --- /dev/null +++ b/tools/python3/lib/rt_m1_client/session.py @@ -0,0 +1,187 @@ +#!/usr/bin/python3 +#============================================================================== +# 5G-MAG Reference Tools: M1 Session +#============================================================================== +# +# File: rt_m1_client/session.py +# License: 5G-MAG Public License (v1.0) +# Author: David Waring +# Copyright: (C) 2023 British Broadcasting Corporation +# +# For full license terms please see the LICENSE file distributed with this +# program. If this file is missing then the license can be retrieved from +# https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +# +#============================================================================== +# +# M1 Session class +# =============== +# +# This module contains an M1 Session management class written in Python 3 using +# asyncio. This class uses an M1Client object to communicate with the 5GMS +# Application Function via the interface at reference point M1. +# +# The module will maintain a persistent list of provisioning sessions and assist +# in managing the resources for those provisioning sessions. +# +'''5G-MAG Reference Tools: M1 Session class +======================================== + +This class provides an interface for managing provisioning sessions on a 5GMS +Application Function. + +This class uses the M1Client class to communicate with the 5GMS Application +Function via the interface at reference point M1. +''' +import logging +from typing import Optional, Union, Tuple, Dict, Any, TypedDict + +from .exceptions import (M1ClientError, M1ServerError, M1Error) +from .types import (ApplicationId, ContentHostingConfiguration, ContentProtocols, + ProvisioningSessionType, ProvisioningSession, ResourceId) +from .client import (M1Client, ProvisioningSessionResponse, ContentHostingConfigurationResponse, ServerCertificateResponse, ServerCertificateSigningRequestResponse, ContentProtocolsResponse) +from .data_store import DataStore + +class M1Session: + '''M1 Session management class + =========================== + + This class is used as the top level class to manage a communication session + with the 5GMS Application Function. + ''' + async def __init__(self, host_address: Tuple[str,int], persistent_data_store: Optional[DataStore] = None): + self.__m1_host = host_address + self.__data_store_dir = persistent_data_store + self.__m1_client = None + self.__provisioning_sessions = {} + await self.__reloadFromDataStore() + + # Provisioning Session Management + + async def provisioningSessionIds(self): + '''Get the list of current known provisioning session ids + ''' + return self.__provisioning_sessions.keys() + + async def provisioningSessionProtocols(self, provisioning_session_id: ResourceId) -> Optional[ContentProtocols]: + '''Get the ContentProtocols for the existing provisioning session + ''' + if provisioning_session_id not in self.__provisioning_sessions: + return None + await self.__cacheProtocols(provisioning_session_id) + return self.__provisioning_sessions[provisioning_session_id]['protocols']['ContentProtocols'] + + async def provisioningSessionCertificateIds(self, provisioning_session_id: ResourceId) -> Optional[List[ResourceId]]: + if provisioning_session_id not in self.__provisioning_sessions: + return None + await self.__cacheProvisioningSession(provisioning_session_id) + ps = self.__provisioning_sessions[provisioning_session_id]['ProvisioningSession'] + if 'certificates' not in ps: + return [] + return ps['certificates'] + + async def provisioningSessionContentHostingConfiguration(self, provisioning_session_id: ResourceId) -> Optional[ContentHostingConfiguration]: + if provisioning_session_id not in self.__provisioning_sessions: + return None + await self.__cacheContentHostingConfiguration(provisioning_session_id) + ps = self.__provisioning_sessions[provisioning_session_id] + chc_resp = ps['content-hosting-configuration'] + if chc_resp is None: + return None + chc = chc_resp['ContentHostingConfiguration'] + return chc + + async def provisioningSessionDestroy(self, provisioning_session_id: ResourceId) -> Optional[bool]: + if provisioning_session_id not in self.__provisioning_sessions: + return None + await self.__connect() + return await self.__m1_client.destroyProvisioningSession(prov_sess) + + # Certificates management + + async def certificateIds(self, provisioning_session_id: ResourceId) -> Optional[List[ResourceId]]: + if provisioning_session_id not in self.__provisioning_sessions: + return None + await self.__cacheProvisioningSession(provisioning_session_id) + ps = self.__provisioning_sessions[provisioning_session_id]['ProvisioningSession'] + if 'certificates' not in ps: + return [] + return ps['certificates'] + + async def newCertificate(self, provisioning_session_id: ResourceId) -> Optional[ResourceId]: + + + async def newCertificateSigningRequest(self, provisioning_session_id: ResourceId) -> Optional[str]: + + # Private methods + + async def __reloadFromDataStore(self): + if self.__data_store_dir is None: + return + + sessions = self.__data_store_dir.get('provisioning_sessions'); + + # Check the provisioning session still exist with the AF + await self.__connect() + to_remove = [] + for prov_sess in sessions: + if await self.__m1_client.getProvisioningSessionById(prov_sess) is None: + to_remove += [prov_sess] + for prov_sess in to_remove: + sessions.remove(prov_sess) + + # Populate provisioning session resource keys + self.__provisioning_sessions = {} + for prov_sess in sessions: + self.__provisioning_sessions[prov_sess] = None + + async def __cacheResources(self): + if len(self.__provisioning_sessions) == 0: + return + for prov_sess in self.__provisioning_sessions.keys(): + self.__cacheProvisioningSession(prov_sess) + + async def __cacheProvisioningSession(self, prov_sess: ResourceId): + ps = self.__provisioning_sessions[prov_sess] + now = datetime.datetime.now(datetime.timezone.utc) + if ps is None or ps['cache-until'] is None or ps['cache-until'] < now: + await self.__connect() + result = await self.__m1_client.getProvisioningSessionById(prov_sess) + if result is not None: + ps.update(result) + ps.update({ + 'protocols': None, + 'content-hosting-configuration': None, + }) + + async def __cacheProtocols(self, provisioning_session_id: ResourceId): + await self.__cacheProvisioningSession(provisioning_session_id) + ps = self.__provisioning_sessions[provisioning_session_id] + now = datetime.datetime.now(datetime.timezone.utc) + if ps['protocols'] is None or ps['protocols']['cache-until'] is None or ps['protocols']['cache-until'] < now: + await self.__connect() + result = await self.__m1_client.getContentProtocols(provisioning_session_id) + if result is not None: + ps['protocols'].update(result) + + async def __cacheContentHostingConfiguration(self, provisioning_session_id: ResourceId): + await self.__cacheProvisioningSession(provisioning_session_id) + ps = self.__provisioning_sessions[provisioning_session_id] + now = datetime.datetime.now(datetime.timezone.utc) + chc = ps['content-hosting-configuration'] + if chc is None or chc['cache-until'] is None or chc['cache-until'] < now: + await self.__connect() + result = await self.__m1_client.retrieveContentHostingConfiguration(provisioning_session_id) + if result is not None: + chc.update(result) + else: + ps['content-hosting-configuration'] = None + + async def __connect(self): + if self.__m1_client is None: + self.__m1_client = M1Client(self.__m1_host) + +__all__ = [ + # Classes + 'M1Session', + ] diff --git a/tools/python3/m1_session_cli.py b/tools/python3/m1_session_cli.py new file mode 100755 index 0000000..0494a74 --- /dev/null +++ b/tools/python3/m1_session_cli.py @@ -0,0 +1,72 @@ +#!/usr/bin/python3 +#============================================================================== +# 5G-MAG Reference Tools: M1 Session CLI +#============================================================================== +# +# File: m1_session_cli.py +# License: 5G-MAG Public License (v1.0) +# Author: David Waring +# Copyright: (C) 2023 British Broadcasting Corporation +# +# For full license terms please see the LICENSE file distributed with this +# program. If this file is missing then the license can be retrieved from +# https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +# +#============================================================================== +# +# M1 Session CLI +# =============== +# +# This is a command line tool to perform operations on the 5GMS Application +# Function via the M1 interface. +# +'''5G-MAG Reference Tools: M1 Session CLI + +Perform operations on the 5GMS Application Function via the interface at +reference point M1. + +Syntax: + m1-session-cli -h + m1-session-cli configure show + m1-session-cli configure set + m1-session-cli configure get + m1-session-cli list [-v] + m1-session-cli new-stream [--with-ssl|--ssl-only] [] + m1-session-cli del-stream -p + m1-session-cli del-stream [] + m1-session-cli check-certificate-renewal + m1-session-cli renew-certificate -p + m1-session-cli renew-certificate [] +''' + +import asyncio +import sys + +from rt_m1_client.session import M1Session +from rt_m1_client.exceptions import M1Error +from rt_m1_client.data_store import JSONFileDataStore + +async def main(): + ''' + Async application entry point + ''' + try: + data_store = JSONFileDataStore('m1-client-datastore') + m1_session = M1Session(('127.0.0.22', 7778), data_store) + provisioning_session_id = await m1_session.createNewDownlinkPullStream('https://ftp.itec.aau.at/datasets/DASHDataset2014/BigBuckBunny/4sec/', 'BigBuckBunny_4s_onDemand_2014_05_09.mpd', name='Test CHC', ssl=True, insecure=False, app_id='myAppId', asp_id='myAspId') + print(f'Created Provisioning Session: {provisioning_session_id}') + prov_sess = m1_session.getProvisioningSession(provisioning_session_id) + print(f'ProvisioningSession = {repr(prov_sess)}') + except M1Error as err: + print(f'Communication error: {err}') + return 2 + return 0 + +def app(): + ''' + Application entry point + ''' + return asyncio.run(main()) + +if __name__ == '__main__': + sys.exit(app()) From 7c9ad84f6e386ddf042c5790619e8bc4ce349b5c Mon Sep 17 00:00:00 2001 From: David Waring Date: Mon, 6 Mar 2023 17:18:28 +0000 Subject: [PATCH 20/48] Ignore build and install directories during git commands --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 8d35cb3..1b19217 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ __pycache__ *.pyc +build +install From 2a6472df247815d0e4a93892e50b3784ef4db4d3 Mon Sep 17 00:00:00 2001 From: David Waring Date: Fri, 10 Mar 2023 01:21:44 +0000 Subject: [PATCH 21/48] Improve error handling --- src/5gmsaf/context.c | 6 ++-- src/5gmsaf/msaf-sm.c | 51 +++++++++++++++++++++++++------ src/5gmsaf/provisioning-session.c | 46 ++++++++++++++++------------ src/5gmsaf/provisioning-session.h | 4 +-- 4 files changed, 74 insertions(+), 33 deletions(-) diff --git a/src/5gmsaf/context.c b/src/5gmsaf/context.c index fd35298..a764198 100644 --- a/src/5gmsaf/context.c +++ b/src/5gmsaf/context.c @@ -651,10 +651,10 @@ int msaf_context_server_name_set(void) { self->server_name, sizeof(self->server_name), NULL, 0, NI_NAMEREQD); if (res) { - printf("error: %d\n", res); + ogs_error("error retrieving server name: %d\n", res); + } else { + ogs_debug("node=%s", self->server_name); } - else - printf("node=%s\n", self->server_name); return 0; } diff --git a/src/5gmsaf/msaf-sm.c b/src/5gmsaf/msaf-sm.c index 198181a..3f2fb0f 100644 --- a/src/5gmsaf/msaf-sm.c +++ b/src/5gmsaf/msaf-sm.c @@ -473,19 +473,52 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) cJSON *provisioning_session; char *provisioning_session_type, *external_app_id, *asp_id = NULL; msaf_provisioning_session_t *msaf_provisioning_session; + + ogs_debug("createProvisioningSession: received=\"%s\"", request->http.content); + + entry = cJSON_GetObjectItemCaseSensitive(prov_sess, "provisioningSessionType"); + if (!entry) { + const char *err = "createProvisioningSession: \"provisioningSessionType\" is not present"; + ogs_error(err); + ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); + break; + } + if (!cJSON_IsString(entry)) { + const char *err = "createProvisioningSession: \"provisioningSessionType\" is not a string"; + ogs_error(err); + ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); + break; + } + provisioning_session_type = entry->valuestring; - cJSON_ArrayForEach(entry, prov_sess) { - if(!strcmp(entry->string, "provisioningSessionType")){ - provisioning_session_type = entry->valuestring; - } - if(!strcmp(entry->string, "aspId")){ - asp_id = entry->valuestring; - } - if(!strcmp(entry->string, "externalApplicationId")){ - external_app_id = entry->valuestring; + entry = cJSON_GetObjectItemCaseSensitive(prov_sess, "externalApplicationId"); + if (!entry) { + const char *err = "createProvisioningSession: \"externalApplicationId\" is not present"; + ogs_error(err); + ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); + break; + } + if (!cJSON_IsString(entry)) { + const char *err = "createProvisioningSession: \"externalApplicationId\" is not a string"; + ogs_error(err); + ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); + break; + } + external_app_id = entry->valuestring; + + entry = cJSON_GetObjectItemCaseSensitive(prov_sess, "aspId"); + if (entry) { + if (!cJSON_IsString(entry)) { + const char *err = "createProvisioningSession: \"aspId\" is not a string"; + ogs_error(err); + ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); + break; } + asp_id = entry->valuestring; } + msaf_provisioning_session = msaf_provisioning_session_create(provisioning_session_type, asp_id, external_app_id); + provisioning_session = msaf_provisioning_session_get_json(msaf_provisioning_session->provisioningSessionId); if (provisioning_session != NULL) { ogs_sbi_response_t *response; diff --git a/src/5gmsaf/provisioning-session.c b/src/5gmsaf/provisioning-session.c index 94001c9..dfb35dc 100644 --- a/src/5gmsaf/provisioning-session.c +++ b/src/5gmsaf/provisioning-session.c @@ -9,13 +9,15 @@ program. If this file is missing then the license can be retrieved from */ #include -#include "provisioning-session.h" #include "application-server-context.h" #include "media-player-entry.h" +#include "certmgr.h" #include "context.h" #include "utilities.h" #include "hash.h" +#include "provisioning-session.h" + typedef struct free_ogs_hash_provisioning_session_s { char *provisioning_session; ogs_hash_t *hash; @@ -65,15 +67,19 @@ msaf_content_hosting_configuration_with_af_unique_cert_id(msaf_provisioning_sess } msaf_provisioning_session_t * -msaf_provisioning_session_create(char *provisioning_session_type, char *asp_id, char *external_app_id) +msaf_provisioning_session_create(const char *provisioning_session_type, const char *asp_id, const char *external_app_id) { msaf_provisioning_session_t *msaf_provisioning_session; ogs_uuid_t uuid; char id[OGS_UUID_FORMATTED_LENGTH + 1]; OpenAPI_provisioning_session_t *provisioning_session; + char *prov_sess_type; + + prov_sess_type = ogs_strdup(provisioning_session_type); ogs_uuid_get(&uuid); ogs_uuid_format(id, &uuid); - provisioning_session = OpenAPI_provisioning_session_create(ogs_strdup(id), OpenAPI_provisioning_session_type_FromString(provisioning_session_type), (asp_id)?ogs_strdup(asp_id):NULL, ogs_strdup(external_app_id), NULL, NULL, NULL, NULL, NULL, NULL); + provisioning_session = OpenAPI_provisioning_session_create(ogs_strdup(id), OpenAPI_provisioning_session_type_FromString(prov_sess_type), (asp_id)?ogs_strdup(asp_id):NULL, ogs_strdup(external_app_id), NULL, NULL, NULL, NULL, NULL, NULL); + ogs_free(prov_sess_type); msaf_provisioning_session = ogs_calloc(1, sizeof(msaf_provisioning_session_t)); ogs_assert(msaf_provisioning_session); @@ -104,35 +110,35 @@ msaf_provisioning_session_get_json(const char *provisioning_session_id) { msaf_provisioning_session_t *msaf_provisioning_session; - cJSON *provisioning_session_json; - - OpenAPI_provisioning_session_t *provisioning_session = NULL; - provisioning_session = ogs_malloc(sizeof(OpenAPI_provisioning_session_t)); - ogs_assert(provisioning_session); + cJSON *provisioning_session_json = NULL; msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(provisioning_session_id); if (msaf_provisioning_session) { + OpenAPI_provisioning_session_t *provisioning_session; + ogs_hash_index_t *cert_node; + + provisioning_session = ogs_calloc(1,sizeof(OpenAPI_provisioning_session_t)); + ogs_assert(provisioning_session); provisioning_session->provisioning_session_id = msaf_provisioning_session->provisioningSessionId; provisioning_session->provisioning_session_type = msaf_provisioning_session->provisioningSessionType; - provisioning_session->asp_id = msaf_provisioning_session->aspId; + provisioning_session->asp_id = msaf_provisioning_session->aspId; provisioning_session->external_application_id = msaf_provisioning_session->externalApplicationId; - provisioning_session->server_certificate_ids = NULL; - provisioning_session->content_preparation_template_ids = NULL; - provisioning_session->metrics_reporting_configuration_ids = NULL; - provisioning_session->policy_template_ids = NULL; - provisioning_session->edge_resources_configuration_ids = NULL; - provisioning_session->event_data_processing_configuration_ids = NULL; + provisioning_session->server_certificate_ids = (OpenAPI_set_t*)OpenAPI_list_create(); + for (cert_node=ogs_hash_first(msaf_provisioning_session->certificate_map); cert_node; cert_node=ogs_hash_next(cert_node)) { + ogs_debug("msaf_provisioning_session_get_json: Add cert %s", ogs_hash_this_key(cert_node)); + OpenAPI_list_add(provisioning_session->server_certificate_ids, (void*)ogs_hash_this_key(cert_node)); + } provisioning_session_json = OpenAPI_provisioning_session_convertToJSON(provisioning_session); + + OpenAPI_list_free(provisioning_session->server_certificate_ids); + ogs_free(provisioning_session); } else { ogs_error("Unable to retrieve Provisioning Session"); - ogs_free(provisioning_session); - return NULL; } - ogs_free(provisioning_session); return provisioning_session_json; } @@ -520,7 +526,7 @@ int uri_relative_check(char *entry_point_path) char *enumerate_provisioning_sessions(void) { - ogs_hash_index_t *hi, *next_hi; + ogs_hash_index_t *hi; char *provisioning_sessions = "[]"; int number_of_provisioning_sessions = ogs_hash_count(msaf_self()->provisioningSessions_map); if (number_of_provisioning_sessions) @@ -655,3 +661,5 @@ tidy_relative_path_re(void) } } +/* vim:ts=8:sts=4:sw=4:expandtab: + */ diff --git a/src/5gmsaf/provisioning-session.h b/src/5gmsaf/provisioning-session.h index 93b47b0..9c219b9 100644 --- a/src/5gmsaf/provisioning-session.h +++ b/src/5gmsaf/provisioning-session.h @@ -34,14 +34,14 @@ typedef struct msaf_provisioning_session_s { char *contentHostingConfigurationHash; time_t serviceAccessInformationCreated; char *serviceAccessInformationHash; - ogs_list_t certificates; //Nodes for this list are msaf_assigned_certificate_t * + /*ogs_list_t certificates; //Nodes for this list are msaf_assigned_certificate_t * */ ogs_hash_t *certificate_map; ogs_list_t msaf_application_servers; // Nodes for this list are msaf_application_server_node_t * ogs_list_t msaf_application_server_state_nodes; //Nodes for this list are msaf_application_server_state_node_t * int marked_for_deletion; } msaf_provisioning_session_t; -extern msaf_provisioning_session_t *msaf_provisioning_session_create(char *provisioning_session_type, char *asp_id, char *external_app_id); +extern msaf_provisioning_session_t *msaf_provisioning_session_create(const char *provisioning_session_type, const char *asp_id, const char *external_app_id); extern msaf_provisioning_session_t *msaf_provisioning_session_find_by_provisioningSessionId(const char *provisioningSessionId); extern cJSON *msaf_provisioning_session_get_json(const char *provisioning_session_id); From 475b98de5ac32ffb1f9ae8a59fb4e00394ff7e90 Mon Sep 17 00:00:00 2001 From: David Waring Date: Fri, 10 Mar 2023 01:23:01 +0000 Subject: [PATCH 22/48] Implement configure, list and new-stream session management commands --- tools/python3/lib/rt_m1_client/client.py | 18 +- tools/python3/lib/rt_m1_client/data_store.py | 28 +- tools/python3/lib/rt_m1_client/session.py | 181 +++++++++++-- tools/python3/lib/rt_m1_client/types.py | 24 +- tools/python3/m1_session_cli.py | 268 ++++++++++++++++++- 5 files changed, 486 insertions(+), 33 deletions(-) diff --git a/tools/python3/lib/rt_m1_client/client.py b/tools/python3/lib/rt_m1_client/client.py index b9f0090..a9d8f34 100644 --- a/tools/python3/lib/rt_m1_client/client.py +++ b/tools/python3/lib/rt_m1_client/client.py @@ -93,7 +93,7 @@ def __init__(self, host_address: Tuple[str,int]): ''' self.__host_address = host_address self.__connection = None - self.__log = logging.getLogger(__name__) + self.__log = logging.getLogger(__name__ + '.' + self.__class__.__name__) # TS26512_M1_ProvisioningSession @@ -588,7 +588,9 @@ def __default_response(self, result: Dict[str,Any]) -> None: @staticmethod def __tag_and_date(result: Dict[str,Any]) -> TagAndDateResponse: + # Get ETag ret = {'ETag': result['headers'].get('etag')} + # Get Last-Modified as a datetime.datetime lm_dt = result['headers'].get('last-modified') if lm_dt is not None: try: @@ -605,6 +607,20 @@ def __tag_and_date(result: Dict[str,Any]) -> TagAndDateResponse: except ValueError: lm_dt = None ret['Last-Modified'] = lm_dt + # Get Cache-Control as a cache expiry time + cc = result['headers'].get('cache-control') + if cc is not None: + age = result['headers'].get('age') + if age is None: + age = 0 + else: + age = int(age) + max_age_values = [int(c[8:]) for c in [v.strip() for v in cc.split(',')] if c[:8] == 'max-age='] + if len(max_age_values) > 0: + cc = datetime.datetime.now(tz=datetime.timezone.utc)+datetime.timedelta(seconds=min(max_age_values)-age) + else: + cc = None + ret['Cache-Until'] = cc return ret def __debug(self, *args, **kwargs): diff --git a/tools/python3/lib/rt_m1_client/data_store.py b/tools/python3/lib/rt_m1_client/data_store.py index 4b0bcac..abb7aa1 100644 --- a/tools/python3/lib/rt_m1_client/data_store.py +++ b/tools/python3/lib/rt_m1_client/data_store.py @@ -32,19 +32,22 @@ The JSONFileDataStore class is an implementation that stores the data being represented in JSON notation as a set of files. ''' +import aiofiles import json import logging +import os +import os.path from typing import Any class DataStore: '''DataStore base class ''' - def get(self, key: str, default: Any = None) -> Any: + async def get(self, key: str, default: Any = None) -> Any: '''Get a persisted value by key name ''' raise NotImplementedError('DataStore implementation should override this method') - def set(self, key: str, value: Any) -> bool: + async def set(self, key: str, value: Any) -> bool: '''Store a persisted value using the key name ''' raise NotImplementedError('DataStore implementation should override this method') @@ -58,22 +61,29 @@ def __init__(self, data_store_dir: str): self.__dir = data_store_dir if not os.path.exists(self.__dir): os.makedirs(self.__dir) - if not os.path.is_dir(self.__dir): + if not os.path.isdir(self.__dir): raise RuntimeError(f'{self.__dir} is not a directory') - def get(self, key: str, default: Any = None) -> Any: + def __await__(self): + return self.__self().__await__() + + async def __self(self): + return self + + async def get(self, key: str, default: Any = None) -> Any: '''Get a persisted value by key name ''' json_file = os.path.join(self.__dir, f'{key}.json') - if not os.path.exists(json_file) or not os.path.is_file(json_file): + if not os.path.exists(json_file) or not os.path.isfile(json_file): return default - val = json.load(json_file) + with open(json_file, 'r') as json_in: + val = json.load(json_in) return val - def set(self, key: str, value: Any) -> bool: + async def set(self, key: str, value: Any) -> bool: '''Store a persisted value using the key name ''' json_file = os.path.join(self.__dir, f'{key}.json') - with open(json_file, 'w') as json_out: - json_out.write(json.dumps(value)) + async with aiofiles.open(json_file, mode='w') as json_out: + await json_out.write(json.dumps(value)) return True diff --git a/tools/python3/lib/rt_m1_client/session.py b/tools/python3/lib/rt_m1_client/session.py index 3f70d42..0a34923 100644 --- a/tools/python3/lib/rt_m1_client/session.py +++ b/tools/python3/lib/rt_m1_client/session.py @@ -33,13 +33,15 @@ This class uses the M1Client class to communicate with the 5GMS Application Function via the interface at reference point M1. ''' +import datetime import logging -from typing import Optional, Union, Tuple, Dict, Any, TypedDict +from typing import Optional, Union, Tuple, Dict, Any, TypedDict, List from .exceptions import (M1ClientError, M1ServerError, M1Error) -from .types import (ApplicationId, ContentHostingConfiguration, ContentProtocols, - ProvisioningSessionType, ProvisioningSession, ResourceId) -from .client import (M1Client, ProvisioningSessionResponse, ContentHostingConfigurationResponse, ServerCertificateResponse, ServerCertificateSigningRequestResponse, ContentProtocolsResponse) +from .types import (ApplicationId, ContentHostingConfiguration, ContentProtocols, ProvisioningSessionType, ProvisioningSession, + ResourceId, PROVISIONING_SESSION_TYPE_DOWNLINK) +from .client import (M1Client, ProvisioningSessionResponse, ContentHostingConfigurationResponse, ServerCertificateResponse, + ServerCertificateSigningRequestResponse, ContentProtocolsResponse) from .data_store import DataStore class M1Session: @@ -49,12 +51,19 @@ class M1Session: This class is used as the top level class to manage a communication session with the 5GMS Application Function. ''' - async def __init__(self, host_address: Tuple[str,int], persistent_data_store: Optional[DataStore] = None): + def __init__(self, host_address: Tuple[str,int], persistent_data_store: Optional[DataStore] = None): self.__m1_host = host_address self.__data_store_dir = persistent_data_store self.__m1_client = None self.__provisioning_sessions = {} + self.__log = logging.getLogger(__name__ + '.' + self.__class__.__name__) + + def __await__(self): + return self.__asyncInit().__await__() + + async def __asyncInit(self): await self.__reloadFromDataStore() + return self # Provisioning Session Management @@ -69,24 +78,32 @@ async def provisioningSessionProtocols(self, provisioning_session_id: ResourceId if provisioning_session_id not in self.__provisioning_sessions: return None await self.__cacheProtocols(provisioning_session_id) - return self.__provisioning_sessions[provisioning_session_id]['protocols']['ContentProtocols'] + return self.__provisioning_sessions[provisioning_session_id]['protocols']['contentprotocols'] async def provisioningSessionCertificateIds(self, provisioning_session_id: ResourceId) -> Optional[List[ResourceId]]: + '''Get the list of certificate Ids for a provisioning session + ''' if provisioning_session_id not in self.__provisioning_sessions: return None await self.__cacheProvisioningSession(provisioning_session_id) - ps = self.__provisioning_sessions[provisioning_session_id]['ProvisioningSession'] + ps = self.__provisioning_sessions[provisioning_session_id]['provisioningsession'] if 'certificates' not in ps: return [] return ps['certificates'] async def provisioningSessionContentHostingConfiguration(self, provisioning_session_id: ResourceId) -> Optional[ContentHostingConfiguration]: + '''Get the ContentHostingConfiguration associated with the provisioning session + + Returns None if the provisioning session does not exist or if there is no ContentHostingConfiguration associated with the + provisioning session. + ''' if provisioning_session_id not in self.__provisioning_sessions: return None await self.__cacheContentHostingConfiguration(provisioning_session_id) ps = self.__provisioning_sessions[provisioning_session_id] chc_resp = ps['content-hosting-configuration'] if chc_resp is None: + # Nothing got cached from the AF, probably an error, but no CHC found return None chc = chc_resp['ContentHostingConfiguration'] return chc @@ -95,7 +112,23 @@ async def provisioningSessionDestroy(self, provisioning_session_id: ResourceId) if provisioning_session_id not in self.__provisioning_sessions: return None await self.__connect() - return await self.__m1_client.destroyProvisioningSession(prov_sess) + result = await self.__m1_client.destroyProvisioningSession(prov_sess) + if result: + del self.__provisioning_sessions[provisioning_session_id] + if self.__data_store_dir: + await self.__data_store_dir.set('provisioning_sessions', list(self.__provisioning_sessions.keys())) + + async def provisioningSessionCreate(self, prov_type: ProvisioningSessionType, app_id: ApplicationId, asp_id: ApplicationId): + await self.__connect() + prov_sess_resp: ProvisioningSessionResponse = await self.__m1_client.createProvisioningSession(prov_type, app_id, asp_id) + if prov_sess_resp is None: + self.__log.debug("provisioningSessionCreate: no response") + return None + ps_id = prov_sess_resp['ProvisioningSessionId'] + self.__provisioning_sessions[ps_id] = None + if self.__data_store_dir: + await self.__data_store_dir.set('provisioning_sessions', list(self.__provisioning_sessions.keys())) + return ps_id # Certificates management @@ -103,15 +136,105 @@ async def certificateIds(self, provisioning_session_id: ResourceId) -> Optional[ if provisioning_session_id not in self.__provisioning_sessions: return None await self.__cacheProvisioningSession(provisioning_session_id) - ps = self.__provisioning_sessions[provisioning_session_id]['ProvisioningSession'] - if 'certificates' not in ps: + ps = self.__provisioning_sessions[provisioning_session_id]['provisioningsession'] + if 'serverCertificateIds' not in ps: return [] - return ps['certificates'] + return ps['serverCertificateIds'] + + async def certificateCreate(self, provisioning_session_id: ResourceId) -> Optional[ResourceId]: + if provisioning_session_id not in self.__provisioning_sessions: + return None + await self.__connect() + cert_resp: ServerCertificateResponse = await self.__m1_client.createServerCertificate(provisioning_session_id) + if cert_resp is None: + return None + cert_id = cert_resp['ServerCertificateId'] + ps = await self.__getProvisioningSessionCache(provisioning_session_id) + if ps is not None: + if 'certificates' not in ps or ps['certificates'] is None: + ps['certificates'] = [cert_id] + elif cert_id not in ps['certificates']: + ps['certificates'] += [cert_id] + return cert_id - async def newCertificate(self, provisioning_session_id: ResourceId) -> Optional[ResourceId]: + async def certificateNewSigningRequest(self, provisioning_session_id: ResourceId) -> Optional[Tuple[ResourceId,str]]: + if provisioning_session_id not in self.__provisioning_sessions: + return None + await self.__connect() + cert_resp: ServerCertificateSigningRequestResponse = await self.__m1_client.reserveServerCertificate( + provisioning_session_id) + if cert_resp is None: + return None + cert_id = cert_resp['ServerCertificateId'] + ps = await self.__getProvisioningSessionCache(provisioning_session_id) + if ps is not None: + if 'certificates' not in ps or ps['certificates'] is None: + ps['certificates'] = [cert_id] + elif cert_id not in ps['certificates']: + ps['certificates'] += [cert_id] + return (cert_id,cert_resp['CertificateSigningRequestPEM']) + # ContentHostingConfiguration methods - async def newCertificateSigningRequest(self, provisioning_session_id: ResourceId) -> Optional[str]: + async def contentHostingConfigurationCreate(self, provisioning_session: ResourceId, chc: ContentHostingConfiguration) -> bool: + if provisioning_session not in self.__provisioning_sessions: + return False + await self.__connect() + chc_resp: Union[bool,ContentHostingConfigurationResponse] = await self.__m1_client.createContentHostingConfiguration( + provisioning_session, chc) + if isinstance(chc_resp,bool): + return chc_resp + ps = await self.__getProvisioningSessionCache(provisioning_session) + if ps is not None: + ps['content-hosting-configuration'] = {k.lower(): v for k,v in chc_resp.items()} + return True + + async def contentHostingConfigurationGet(self, provisioning_session: ResourceId) -> Optional[ContentHostingConfiguration]: + if provisioning_session not in self.__provisioning_sessions: + return None + await self.__cacheContentHostingConfiguration(provisioning_session) + ps = await self.__getProvisioningSessionCache(provisioning_session) + if ps is None: + return None + return ContentHostingConfiguration(ps['content-hosting-configuration']['contenthostingconfiguration']) + + # Convenience methods + + async def createNewDownlinkPullStream(self, ingesturl, entrypoint, app_id, name=None, asp_id=None, ssl=False, insecure=True): + # Create a new provisioning session + provisioning_session: ResourceId = await self.provisioningSessionCreate(PROVISIONING_SESSION_TYPE_DOWNLINK, app_id, asp_id) + if provisioning_session is None: + raise RuntimeError('Failed to create a provisioning session') + # Create an SSL certificate if requested + if ssl: + cert: Optional[ResourceId] = await self.certificateCreate(provisioning_session) + if cert is None: + if insecure: + self.__log.warn('Failed to create hosting with HTTPS, continuing with just HTTP') + else: + raise RuntimeError('Failed to create hosting, unable to create SSL certificate') + # If no name given, generate one + if name is None: + name = self.__next_auto_stream_name() + # Build and send the ContentHostingConfiguration + chc: ContentHostingConfiguration = { + 'name': name, + 'ingestConfiguration': { + 'pull': True, + 'protocol': 'urn:3gpp:5gms:content-protocol:http-pull-ingest', + 'baseURL': ingesturl, + }, + 'distributionConfigurations': [] + } + if ssl and cert is not None: + chc['distributionConfigurations'] += [{'certificateId': cert}] + if insecure: + chc['distributionConfigurations'] += [{}] + if entrypoint is not None: + chc['entryPointPath'] = entrypoint + if not await self.contentHostingConfigurationCreate(provisioning_session, chc): + raise RuntimeError('Failed to create the content hosting configuration') + return True # Private methods @@ -119,7 +242,9 @@ async def __reloadFromDataStore(self): if self.__data_store_dir is None: return - sessions = self.__data_store_dir.get('provisioning_sessions'); + sessions = await self.__data_store_dir.get('provisioning_sessions'); + if sessions is None: + return # Check the provisioning session still exist with the AF await self.__connect() @@ -127,14 +252,23 @@ async def __reloadFromDataStore(self): for prov_sess in sessions: if await self.__m1_client.getProvisioningSessionById(prov_sess) is None: to_remove += [prov_sess] - for prov_sess in to_remove: - sessions.remove(prov_sess) + if len(to_remove) > 0: + for prov_sess in to_remove: + sessions.remove(prov_sess) + if self.__data_store_dir: + await self.__data_store_dir.set('provisioning_sessions', sessions) # Populate provisioning session resource keys self.__provisioning_sessions = {} for prov_sess in sessions: self.__provisioning_sessions[prov_sess] = None + async def __getProvisioningSessionCache(self, provisioning_session_id: ResourceId) -> Optional[dict]: + if provisioning_session_id not in self.__provisioning_sessions: + return None + await self.__cacheProvisioningSession(provisioning_session_id) + return self.__provisioning_sessions[provisioning_session_id] + async def __cacheResources(self): if len(self.__provisioning_sessions) == 0: return @@ -148,7 +282,10 @@ async def __cacheProvisioningSession(self, prov_sess: ResourceId): await self.__connect() result = await self.__m1_client.getProvisioningSessionById(prov_sess) if result is not None: - ps.update(result) + if ps is None: + ps = {} + self.__provisioning_sessions[prov_sess] = ps + ps.update({k.lower(): v for k,v in result.items()}) ps.update({ 'protocols': None, 'content-hosting-configuration': None, @@ -162,7 +299,7 @@ async def __cacheProtocols(self, provisioning_session_id: ResourceId): await self.__connect() result = await self.__m1_client.getContentProtocols(provisioning_session_id) if result is not None: - ps['protocols'].update(result) + ps['protocols'].update({k.lower(): v for k,v in result.items()}) async def __cacheContentHostingConfiguration(self, provisioning_session_id: ResourceId): await self.__cacheProvisioningSession(provisioning_session_id) @@ -173,13 +310,19 @@ async def __cacheContentHostingConfiguration(self, provisioning_session_id: Reso await self.__connect() result = await self.__m1_client.retrieveContentHostingConfiguration(provisioning_session_id) if result is not None: - chc.update(result) + if chc is None: + chc = {} + ps['content-hosting-configuration'] = chc + chc.update({k.lower(): v for k,v in result.items()}) else: ps['content-hosting-configuration'] = None async def __connect(self): if self.__m1_client is None: self.__m1_client = M1Client(self.__m1_host) + + def _dump_state(self): + self.__log.debug(repr(self.__provisioning_sessions)) __all__ = [ # Classes diff --git a/tools/python3/lib/rt_m1_client/types.py b/tools/python3/lib/rt_m1_client/types.py index e2bf332..1495ebf 100644 --- a/tools/python3/lib/rt_m1_client/types.py +++ b/tools/python3/lib/rt_m1_client/types.py @@ -51,9 +51,9 @@ def fromJSON(json_str: str) -> "ProvisioningSession": ret: dict = json.loads(json_str) for mandatory_field in ProvisioningSessionMandatory.__required_keys__: if mandatory_field not in ret: - raise TypeError(f'ProvisioningSession must contain a {mandatory_field} field') + raise TypeError(f'ProvisioningSession must contain a {mandatory_field} field: {json_str}') if ret['provisioningSessionType'] not in ProvisioningSessionType.__args__: - raise TypeError(f'ProvisioningSession.provisioningSessionType must be one of: {", ".join(ProvisioningSessionType.__args__)}') + raise TypeError(f'ProvisioningSession.provisioningSessionType must be one of: {", ".join(ProvisioningSessionType.__args__)}: {json_str}') return ProvisioningSession(ret) @@ -194,6 +194,26 @@ def fromJSON(chc_json: str) -> "ContentHostingConfiguration": # Validate against ContentHostingConfiguration type return ContentHostingConfiguration(chc) + @classmethod + def format(cls, chc: "ContentHostingConfiguration") -> str: + return f'''Name: {chc['name']} +Ingest: + Type: {chc['ingestConfiguration']['protocol']} + URL: {chc['ingestConfiguration']['baseURL']} +Distributions: +{cls.__formatDistributions(chc, indent=2)} +''' + + @classmethod + def __formatDistributions(cls, chc: "ContentHostingConfiguration", indent: int = 0) -> str: + prefix = ' '*indent + dists = [] + for d in chc['distributionConfigurations']: + s = f"{prefix}- URL: {d['baseURL']}" + if 'certificateId' in d: + s += f"\n{prefix} Certificate: {d['certificateId']}" + dists += [s] + return '\n'.join(dists) # TS 29.571 ProblemDetail class InvalidParamMandatory(TypedDict): diff --git a/tools/python3/m1_session_cli.py b/tools/python3/m1_session_cli.py index 0494a74..a691112 100755 --- a/tools/python3/m1_session_cli.py +++ b/tools/python3/m1_session_cli.py @@ -39,20 +39,283 @@ m1-session-cli renew-certificate [] ''' +import argparse import asyncio +import configparser +from io import StringIO +import logging +import os +import os.path import sys +from typing import Tuple, List from rt_m1_client.session import M1Session from rt_m1_client.exceptions import M1Error from rt_m1_client.data_store import JSONFileDataStore +from rt_m1_client.types import ContentHostingConfiguration + +class Configuration: + '''App configuration + ''' + + DEFAULT_CONFIG='''[DEFAULT] + log_dir = /var/log/rt-5gms + state_dir = /var/cache/rt-5gms + run_dir = /run/rt-5gms + + [m1-client] + log_level = info + data_store = %(state_dir)s/m1-client + m1_address = localhost + m1_port = 7777 + asp_id = + external_app_id = please-change-this + ''' + + def __init__(self): + self.__config_filename = None + if os.getuid() != 0: + self.__config_filename = os.path.expanduser(os.path.join('~', '.rt-5gms', 'm1-client.conf')) + else: + self.__config_filename = os.path.join(os.path.sep, 'etc', 'rt-5gms', 'm1-client.conf') + self.__default_config = configparser.ConfigParser() + self.__default_config.read_string(self.DEFAULT_CONFIG) + self.__config = configparser.ConfigParser() + self.__config.read_string(self.DEFAULT_CONFIG) + if os.path.exists(self.__config_filename): + self.__config.read(self.__config_filename) + + def isKey(self, key: str) -> str: + if key in self.__default_config['m1-client']: + return key + raise ValueError('Not a valid configuration option') + + def get(self, key: str, default: str = None, raw: bool = False) -> str: + return self.__config.get('m1-client', key, raw=raw, fallback=default) + + def set(self, key: str, value: str) -> bool: + self.isKey(key) + if key in self.__default_config['DEFAULT']: + section = 'DEFAULT' + else: + section = 'm1-client' + self.__config.set(section, key, value) + self.__saveConfig() + return True + + def isDefault(self, key: str) -> bool: + return self.__config.get('m1-client', key) == self.__default_config.get('m1-client', key) + + def getKeys(self) -> List[str]: + return list(self.__default_config['m1-client'].keys()) + + def resetValue(self, key: str) -> bool: + if self.isDefault(key): + return False + return self.set(key, self.__default_config.get('m1-client', key)) + + def __saveConfig(self): + cfgdir = os.path.dirname(self.__config_filename) + if not os.path.exists(cfgdir): + os.makedirs(cfgdir, mode=0o755) + with open(self.__config_filename, 'w') as cfgout: + for section in ['DEFAULT'] + self.__config.sections(): + cfgout.write(f'[{section}]\n') + for key in self.__config[section]: + cfgvalue = self.__config.get(section, key, raw=True) + defvalue = self.__default_config.get(section, key, raw=True) + if (section == 'DEFAULT' or key not in self.__config['DEFAULT']): + if cfgvalue == defvalue: + cfgout.write('#') + cfgout.write(f'{key} = {cfgvalue}\n') + cfgout.write('\n') + + + def __str__(self): + buf = StringIO() + self.__config.write(buf) + return buf.getvalue() + + def __repr__(self): + return f'Configuration(config="{self}")' + +async def cmd_configure_show(args: argparse.Namespace, config: Configuration) -> int: + default_marker = {True: ' (default)', False: ''} + print('Configuration settings:') + print('\n'.join([f'{key} = {config.get(key, raw=True)}{default_marker[config.isDefault(key)]}' for key in config.getKeys()])) + return 0 + +async def cmd_configure_reset(args: argparse.Namespace, config: Configuration) -> int: + config.resetValue(args.key) + return 0 + +async def cmd_configure_get(args: argparse.Namespace, config: Configuration) -> int: + print(f'{args.key}={repr(config.get(args.key))}') + return 0 + +async def cmd_configure_set(args: argparse.Namespace, config: Configuration) -> int: + config.set(args.key, args.value) + return 0 + +async def cmd_list_verbose(args: argparse.Namespace, config: Configuration) -> int: + session = await get_session(config) + for ps_id in await session.provisioningSessionIds(): + print(f'{ps_id}:') + certs = await session.certificateIds(ps_id) + print(' Certificates:') + print('\n'.join([' '+cert for cert in certs])) + chc = await session.contentHostingConfigurationGet(ps_id) + print(' ContentHostingConfiguration:') + print('\n'.join([' '+line for line in ContentHostingConfiguration.format(chc).split('\n')])) + return 0 + +async def cmd_list(args: argparse.Namespace, config: Configuration) -> int: + if args.verbose: + return await cmd_list_verbose(args, config) + session = await get_session(config) + print('\n'.join(await session.provisioningSessionIds())) + return 0 + +async def cmd_new_stream(args: argparse.Namespace, config: Configuration) -> int: + session = await get_session(config) + name = args.name + use_ssl = args.with_ssl or args.ssl_only + use_plain = not args.ssl_only + app_id = args.app_id or config.get('external_app_id') + asp_id = args.asp_id or config.get('asp_id') + provisioning_session_id = await session.createNewDownlinkPullStream(args.ingesturl, args.entrypoint, name=name, ssl=use_ssl, insecure=use_plain, app_id=app_id, asp_id=asp_id) + print(f'Hosting created as provisioning session {provisioning_session_id}') + return 0 + +async def cmd_delete_stream(args: argparse.Namespace, config: Configuration) -> int: + if args.provisioning_session_id is not None: + ps_id = args.provisioning_session_id + else: + ps_id = await session.provisioningSessionIdByIngestUrl(args.ingesturl, args.entrypointsuffix) + if ps_id is None: + print('No such hosting session found') + return 1 + await session.provisioningSessionDestroy(ps_id) + return 0 + +async def cmd_check_all_renewal(args: argparse.Namespace, config: Configuration) -> int: + session = await get_session(config) + for ps_id in await session.provisioningSessionIds(): + chc = await session.getContentHostingConfiguration(ps_id) + # extract current cert ids + # get public cert for each cert id + # check for soon or past expiry + # request a new certificate + # change id in chc and remember old cert ids + # if any cert ids changed in chc upload replacement chc + # delete old certs + return 1 + +async def cmd_renew_certs(args: argparse.Namespace, config: Configuration) -> int: + session = await get_session(config) + ps_id = args.provisioning_session_id + chc = await session.getContentHostingConfiguration(ps_id) + # get list of unique cert ids in chc + # for each cert id in list + # request a new certificate + # change ids in chc for new cert id + # upload replacement chc + # delete old certs + return 1 + +async def parse_args() -> Tuple[argparse.Namespace,Configuration]: + cfg = Configuration() + + parser = argparse.ArgumentParser(prog='m1-session-cli', description='M1 Session Tool') + subparsers = parser.add_subparsers(required=True) + + parser_configure = subparsers.add_parser('configure', help='Local configuration') + configure_subparsers = parser_configure.add_subparsers(required=True) + parser_configure_show = configure_subparsers.add_parser('show', help='Show local configuration') + parser_configure_show.set_defaults(command=cmd_configure_show) + parser_configure_get = configure_subparsers.add_parser('get', help='Get local configuration value') + parser_configure_get.set_defaults(command=cmd_configure_get) + parser_configure_get.add_argument('key', metavar='KEY', type=cfg.isKey) + parser_configure_set = configure_subparsers.add_parser('set', help='Set local configuration value') + parser_configure_set.set_defaults(command=cmd_configure_set) + parser_configure_set.add_argument('key', metavar='KEY', type=cfg.isKey) + parser_configure_set.add_argument('value', metavar='VALUE') + parser_configure_reset = configure_subparsers.add_parser('reset', help='Reset configuration value to its default') + parser_configure_reset.set_defaults(command=cmd_configure_reset) + parser_configure_reset.add_argument('key', metavar='KEY', type=cfg.isKey) + + parser_list = subparsers.add_parser('list', help='List provisioning sessions') + parser_list.set_defaults(command=cmd_list) + parser_list.add_argument('-v', '--verbose', required=False, action='store_true') + + parser_newstream = subparsers.add_parser('new-stream', help='Create a new ingest stream') + parser_newstream.set_defaults(command=cmd_new_stream) + parser_newstream.add_argument('-n', '--name', metavar='NAME', help='The name of the new stream', required=False) + parser_newstream.add_argument('-e', '--external-app-id', dest='app_id', metavar="APPLICATION-ID", help='The external application id to register the stream to', required=False) + parser_newstream.add_argument('-a','--asp-id', metavar="PROVIDER-ID", help="The Application Service Provider Id to use", required=False) + parser_newstream_ssl_options = parser_newstream.add_mutually_exclusive_group(required=False) + parser_newstream_ssl_options.add_argument('--with-ssl', action='store_true') + parser_newstream_ssl_options.add_argument('--ssl-only', action='store_true') + parser_newstream.add_argument('ingesturl', metavar='ingest-URL', help='The ingest URL prefix to use') + parser_newstream.add_argument('entrypoint', metavar='entry-point-URL', nargs='?', + help='The media player entry point suffix.') + + parser_delstream = subparsers.add_parser('del-stream', help='Delete an ingest stream') + parser_delstream.set_defaults(command=cmd_delete_stream) + parser_delstream_filter = parser_delstream.add_mutually_exclusive_group(required=True) + parser_delstream_filter.add_argument('-p', '--provisioning-session', help='Delete by provisioning session id') + #parser_delstream_filter_byurl = parser_delstream_filter.add_argument_group() + #parser_delstream_filter_byurl.add_argument('ingesturl', metavar='ingest-URL', nargs=1, + # help='The ingest URL prefix to use') + #parser_delstream_filter_byurl.add_argument('entrypoint', metavar='entry-point-URL', nargs='?', + # help='The media player entry point suffix.') + parser_delstream_filter.add_argument('ingesturl', metavar='ingest-URL', nargs='?', help='The ingest URL prefix to use') + + parser_checkrenewal = subparsers.add_parser('check-certificate-renewal', help='Renew all certificates if close to expiry') + parser_checkrenewal.set_defaults(command=cmd_check_all_renewal) + + parser_renewcert = subparsers.add_parser('renew-certificate', help='Force renewal of a specific certificate') + parser_renewcert.set_defaults(command=cmd_renew_certs) + parser_renewcert_filter = parser_renewcert.add_mutually_exclusive_group(required=True) + parser_renewcert_filter.add_argument('-p', '--provisioning-session', help='Renew by provisioning session id') + #parser_renewcert_filter_byurl = parser_renewcert_filter.add_argument_group(required=False) + #parser_renewcert_filter_byurl.add_argument('ingesturl', metavar='ingest-URL', nargs=1, + # help='The ingest URL prefix to use') + #parser_renewcert_filter_byurl.add_argument('entrypoint', metavar='entry-point-URL', nargs='?', + # help='The media player entry point suffix.') + parser_renewcert_filter.add_argument('ingesturl', metavar='ingest-URL', nargs='?', help='The ingest URL prefix to use') + + args = parser.parse_args() + + return (args,cfg) + +_m1_session = None + +async def get_session(config: Configuration) -> M1Session: + global _m1_session + if _m1_session is None: + data_store_dir = config.get('data_store') + if data_store_dir is not None: + data_store = await JSONFileDataStore(config.get('data_store')) + else: + data_store = None + _m1_session = await M1Session((config.get('m1_address', 'localhost'), config.get('m1_port',7777)), data_store) + return _m1_session async def main(): ''' Async application entry point ''' try: - data_store = JSONFileDataStore('m1-client-datastore') - m1_session = M1Session(('127.0.0.22', 7778), data_store) + (args, config) = await parse_args() + logging.basicConfig(level={k.lower(): v for k,v in logging.getLevelNamesMapping().items()}[config.get('log_level')]) + log = logging.getLogger() + if hasattr(args, 'command'): + return await args.command(args, config) + else: + print(repr(parse_args())) + return 0 + provisioning_session_id = await m1_session.createNewDownlinkPullStream('https://ftp.itec.aau.at/datasets/DASHDataset2014/BigBuckBunny/4sec/', 'BigBuckBunny_4s_onDemand_2014_05_09.mpd', name='Test CHC', ssl=True, insecure=False, app_id='myAppId', asp_id='myAspId') print(f'Created Provisioning Session: {provisioning_session_id}') prov_sess = m1_session.getProvisioningSession(provisioning_session_id) @@ -66,6 +329,7 @@ def app(): ''' Application entry point ''' + logging.basicConfig(level=logging.INFO) return asyncio.run(main()) if __name__ == '__main__': From 4ef22fd0260fb5e943284761fbd96aabc811d6bb Mon Sep 17 00:00:00 2001 From: deva Date: Fri, 10 Mar 2023 17:06:12 +0000 Subject: [PATCH 23/48] seperate endpoints for M1, M5 and Maf --- src/5gmsaf/context.c | 154 ++- src/5gmsaf/context.h | 22 +- src/5gmsaf/event.c | 30 +- src/5gmsaf/event.h | 14 +- src/5gmsaf/generator-5gmsaf | 2 +- src/5gmsaf/init.c | 44 +- src/5gmsaf/meson.build | 9 +- src/5gmsaf/msaf-fsm.c | 30 + src/5gmsaf/msaf-fsm.h | 34 + src/5gmsaf/msaf-m1-sm.c | 1833 +++++++++++++++++++++++++++++++++++ src/5gmsaf/msaf-m5-sm.c | 308 ++++++ src/5gmsaf/msaf-mgmt-sm.c | 127 +-- src/5gmsaf/msaf-mgmt-sm.h | 31 - src/5gmsaf/msaf-sm.c | 849 +--------------- src/5gmsaf/msaf-sm.h | 15 + 15 files changed, 2458 insertions(+), 1044 deletions(-) create mode 100644 src/5gmsaf/msaf-fsm.c create mode 100644 src/5gmsaf/msaf-fsm.h create mode 100644 src/5gmsaf/msaf-m1-sm.c create mode 100644 src/5gmsaf/msaf-m5-sm.c delete mode 100644 src/5gmsaf/msaf-mgmt-sm.h diff --git a/src/5gmsaf/context.c b/src/5gmsaf/context.c index a764198..d31a00a 100644 --- a/src/5gmsaf/context.c +++ b/src/5gmsaf/context.c @@ -63,11 +63,6 @@ void msaf_context_init(void) self->content_hosting_configuration_file_map = ogs_hash_make(); ogs_assert(self->content_hosting_configuration_file_map); - self->config.app_server_sockaddr = NULL; - self->config.mgmt_server_sockaddr = NULL; - self->config.app_server_sockaddr_v6 = NULL; - self->config.mgmt_server_sockaddr_v6 = NULL; - msaf_server_response_cache_control_set(); } @@ -217,8 +212,8 @@ int msaf_context_parse_config(void) } } msaf_server_response_cache_control_set_from_config(m1_provisioning_session_response_max_age, m1_content_hosting_configurations_response_max_age, m1_server_certificates_response_max_age, m1_content_protocols_response_max_age, m5_service_access_information_response_max_age); - - } else if (!strcmp(msaf_key, "sbi") || !strcmp(msaf_key, "m1ManagementInterface")) { + + } else if (!strcmp(msaf_key, "sbi") || !strcmp(msaf_key, "m1") || !strcmp(msaf_key, "m5") || !strcmp(msaf_key, "maf")) { if(!self->config.open5gsIntegration_flag) { ogs_list_t list, list6; ogs_socknode_t *node = NULL, *node6 = NULL; @@ -325,7 +320,7 @@ int msaf_context_parse_config(void) ogs_warn("unknown key `%s`", sbi_key); } - if (!strcmp(msaf_key, "m1ManagementInterface") && (port == 0)){ + if (port == 0){ ogs_warn("Specify the [%s] port, otherwise a random port will be used", msaf_key); } @@ -364,44 +359,125 @@ int msaf_context_parse_config(void) node = ogs_list_first(&list); if (node) { - ogs_sbi_server_t *server = ogs_sbi_server_add( - node->addr, is_option ? &option : NULL); - ogs_assert(server); + int i; + int matches = 0; + ogs_sbi_server_t *server; + ogs_sockaddr_t *check_addrs[] = { + self->config.sbi_server_sockaddr, + self->config.m1_server_sockaddr, + self->config.m5_server_sockaddr, + self->config.maf_mgmt_server_sockaddr + }; + for (i=0; i<(sizeof(check_addrs)/sizeof(*check_addrs)); i++) { + if (check_addrs[i] && ogs_sockaddr_is_equal(node->addr, check_addrs[i])) { + matches = 1; + break; + } + } + if(!matches) { + server = ogs_sbi_server_add( + node->addr, is_option ? &option : NULL); + ogs_assert(server); - if (addr && ogs_app()->parameter.no_ipv4 == 0) - ogs_sbi_server_set_advertise( - server, AF_INET, addr); - - if (key) server->tls.key = key; - if (pem) server->tls.pem = pem; + + if (addr && ogs_app()->parameter.no_ipv4 == 0) + ogs_sbi_server_set_advertise( + server, AF_INET, addr); + + if (key) server->tls.key = key; + if (pem) server->tls.pem = pem; + } if (!strcmp(msaf_key, "sbi")) { - ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.app_server_sockaddr, server->node.addr)); - + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.sbi_server_sockaddr, server->node.addr)); + if(!self->config.m1_server_sockaddr){ + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.m1_server_sockaddr, server->node.addr)); + } + if(!self->config.m5_server_sockaddr){ + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.m5_server_sockaddr, server->node.addr)); + } + if(!self->config.maf_mgmt_server_sockaddr){ + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.maf_mgmt_server_sockaddr, server->node.addr)); + } } - if (!strcmp(msaf_key, "m1ManagementInterface")) { - - ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.mgmt_server_sockaddr, server->node.addr)); + if (!strcmp(msaf_key, "m1")) { + if(self->config.m1_server_sockaddr){ + ogs_freeaddrinfo(self->config.m1_server_sockaddr); + } + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.m1_server_sockaddr, server->node.addr)); + } + if (!strcmp(msaf_key, "m5")) { + if(self->config.m5_server_sockaddr){ + ogs_freeaddrinfo(self->config.m5_server_sockaddr); + } + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.m5_server_sockaddr, server->node.addr)); + } + if (!strcmp(msaf_key, "maf")) { + if(self->config.maf_mgmt_server_sockaddr){ + ogs_freeaddrinfo(self->config.maf_mgmt_server_sockaddr); + } + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.maf_mgmt_server_sockaddr, server->node.addr)); } } node6 = ogs_list_first(&list6); if (node6) { - ogs_sbi_server_t *server = ogs_sbi_server_add( - node6->addr, is_option ? &option : NULL); - ogs_assert(server); + int i; + int matches = 0; + ogs_sbi_server_t *server; + ogs_sockaddr_t *check_addrs[] = { + self->config.sbi_server_sockaddr_v6, + self->config.m1_server_sockaddr_v6, + self->config.m5_server_sockaddr_v6, + self->config.maf_mgmt_server_sockaddr_v6 + }; + for (i=0; i<(sizeof(check_addrs)/sizeof(*check_addrs)); i++) { + if (check_addrs[i] && ogs_sockaddr_is_equal(node->addr, check_addrs[i])) { + matches = 1; + break; + } + } + if(!matches) { + ogs_sbi_server_t *server = ogs_sbi_server_add( + node6->addr, is_option ? &option : NULL); + ogs_assert(server); - if (addr && ogs_app()->parameter.no_ipv6 == 0) - ogs_sbi_server_set_advertise( - server, AF_INET6, addr); + if (addr && ogs_app()->parameter.no_ipv6 == 0) + ogs_sbi_server_set_advertise( + server, AF_INET6, addr); - if (key) server->tls.key = key; - if (pem) server->tls.pem = pem; + if (key) server->tls.key = key; + if (pem) server->tls.pem = pem; + } if (!strcmp(msaf_key, "sbi")) { - ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.app_server_sockaddr_v6, server->node.addr)); + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.sbi_server_sockaddr_v6, server->node.addr)); + if(!self->config.m1_server_sockaddr_v6){ + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.m1_server_sockaddr_v6, server->node.addr)); + } + if(!self->config.m5_server_sockaddr_v6){ + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.m5_server_sockaddr_v6, server->node.addr)); + } + if(!self->config.maf_mgmt_server_sockaddr_v6){ + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.maf_mgmt_server_sockaddr_v6, server->node.addr)); + } + } + if (!strcmp(msaf_key, "m1")) { + if(self->config.m1_server_sockaddr_v6){ + ogs_freeaddrinfo(self->config.m1_server_sockaddr_v6); + } + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.m1_server_sockaddr_v6, server->node.addr)); } - if (!strcmp(msaf_key, "m1ManagementInterface")) { - ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.mgmt_server_sockaddr_v6, server->node.addr)); + if (!strcmp(msaf_key, "m5")) { + if(self->config.m5_server_sockaddr_v6){ + ogs_freeaddrinfo(self->config.m5_server_sockaddr_v6); + } + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.m5_server_sockaddr_v6, server->node.addr)); + } + if (!strcmp(msaf_key, "maf")) { + if(self->config.maf_mgmt_server_sockaddr_v6){ + ogs_freeaddrinfo(self->config.maf_mgmt_server_sockaddr_v6); + } + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.maf_mgmt_server_sockaddr_v6, server->node.addr)); } } @@ -569,10 +645,14 @@ static void msaf_context_application_server_state_remove_all(void) { } static void msaf_context_server_sockaddr_remove(void){ - if(self->config.app_server_sockaddr) ogs_freeaddrinfo(self->config.app_server_sockaddr); - if(self->config.mgmt_server_sockaddr) ogs_freeaddrinfo(self->config.mgmt_server_sockaddr); - if(self->config.app_server_sockaddr_v6) ogs_freeaddrinfo(self->config.app_server_sockaddr_v6); - if(self->config.mgmt_server_sockaddr_v6) ogs_freeaddrinfo(self->config.app_server_sockaddr_v6); + if(self->config.sbi_server_sockaddr) ogs_freeaddrinfo(self->config.sbi_server_sockaddr); + if(self->config.m1_server_sockaddr) ogs_freeaddrinfo(self->config.m1_server_sockaddr); + if(self->config.m5_server_sockaddr) ogs_freeaddrinfo(self->config.m5_server_sockaddr); + if(self->config.maf_mgmt_server_sockaddr) ogs_freeaddrinfo(self->config.maf_mgmt_server_sockaddr); + if(self->config.sbi_server_sockaddr_v6) ogs_freeaddrinfo(self->config.sbi_server_sockaddr_v6); + if(self->config.m1_server_sockaddr_v6) ogs_freeaddrinfo(self->config.m1_server_sockaddr_v6); + if(self->config.m5_server_sockaddr_v6) ogs_freeaddrinfo(self->config.m5_server_sockaddr_v6); + if(self->config.maf_mgmt_server_sockaddr_v6) ogs_freeaddrinfo(self->config.maf_mgmt_server_sockaddr_v6); } static int msaf_context_prepare(void) diff --git a/src/5gmsaf/context.h b/src/5gmsaf/context.h index aca7a20..dbc4b8d 100644 --- a/src/5gmsaf/context.h +++ b/src/5gmsaf/context.h @@ -19,15 +19,13 @@ program. If this file is missing then the license can be retrieved from #include #include #include - +#include +#include #include "ogs-sbi.h" #include "ogs-app.h" - #include "event.h" #include "msaf-sm.h" - -#include -#include +#include "msaf-fsm.h" #include "openapi/model/content_hosting_configuration.h" #include "openapi/model/service_access_information_resource.h" #include "provisioning-session.h" @@ -49,10 +47,15 @@ typedef struct msaf_configuration_s { ogs_list_t applicationServers_list; ogs_list_t server_addr_list; // Nodes for this list are of type msaf_sbi_addr_t * char *certificateManager; - ogs_sockaddr_t *app_server_sockaddr; - ogs_sockaddr_t *mgmt_server_sockaddr; - ogs_sockaddr_t *app_server_sockaddr_v6; - ogs_sockaddr_t *mgmt_server_sockaddr_v6; + + ogs_sockaddr_t *m1_server_sockaddr; + ogs_sockaddr_t *m5_server_sockaddr; + ogs_sockaddr_t *maf_mgmt_server_sockaddr; + ogs_sockaddr_t *sbi_server_sockaddr; + ogs_sockaddr_t *sbi_server_sockaddr_v6; + ogs_sockaddr_t *m1_server_sockaddr_v6; + ogs_sockaddr_t *m5_server_sockaddr_v6; + ogs_sockaddr_t *maf_mgmt_server_sockaddr_v6; msaf_server_response_cache_control_t *server_response_cache_control; int number_of_application_servers; } msaf_configuration_t; @@ -62,6 +65,7 @@ typedef struct msaf_context_s { ogs_hash_t *provisioningSessions_map; ogs_list_t application_server_states; ogs_hash_t *content_hosting_configuration_file_map; + msaf_fsm_t msaf_fsm; char server_name[NI_MAXHOST]; } msaf_context_t; diff --git a/src/5gmsaf/event.c b/src/5gmsaf/event.c index 31cc502..e742f10 100644 --- a/src/5gmsaf/event.c +++ b/src/5gmsaf/event.c @@ -28,7 +28,8 @@ const char *msaf_event_get_name(msaf_event_t *e) return ogs_event_get_name(&e->h); } -int get_server_type_from_event(msaf_event_t *e) + +int check_event_addresses(msaf_event_t *e, ogs_sockaddr_t *sockaddr_v4, ogs_sockaddr_t *sockaddr_v6) { ogs_sbi_stream_t *stream = e->h.sbi.data; @@ -38,28 +39,13 @@ int get_server_type_from_event(msaf_event_t *e) server = ogs_sbi_server_from_stream(stream); ogs_assert(server); - if (ogs_sockaddr_is_equal(server->node.addr, msaf_self()->config.app_server_sockaddr) == true) { - ogs_info("returns MSAF_APP_SERVER"); - return MSAF_APP_SERVER; - } - - if (ogs_sockaddr_is_equal(server->node.addr, msaf_self()->config.mgmt_server_sockaddr) == true) { - ogs_info("returns MSAF_MGMT_SERVER"); - return MSAF_MGMT_SERVER; - } - - if (ogs_sockaddr_is_equal(server->node.addr, msaf_self()->config.app_server_sockaddr_v6) == true) { - ogs_info("returns MSAF_APP_SERVER"); - return MSAF_APP_SERVER; - } - - if (ogs_sockaddr_is_equal(server->node.addr, msaf_self()->config.mgmt_server_sockaddr_v6) == true) { - ogs_info("returns MSAF_MGMT_SERVER"); - return MSAF_MGMT_SERVER; - - } + if(sockaddr_v4 && (ogs_sockaddr_is_equal(server->node.addr, sockaddr_v4) || (sockaddr_v6 && ogs_sockaddr_is_equal(server->node.addr, sockaddr_v6)) )){ + + return 1; + } + } - return MSAF_APP_SERVER; + return 0; } diff --git a/src/5gmsaf/event.h b/src/5gmsaf/event.h index 7e8589d..b61212b 100644 --- a/src/5gmsaf/event.h +++ b/src/5gmsaf/event.h @@ -15,9 +15,6 @@ program. If this file is missing then the license can be retrieved from #include "ogs-sbi.h" #include "context.h" -#define MSAF_APP_SERVER 0 -#define MSAF_MGMT_SERVER 1 - #ifdef __cplusplus extern "C" { #endif @@ -33,6 +30,14 @@ typedef enum { } msaf_event_e; +typedef enum { + MSAF_SBI_SERVER , + MSAF_M1_SERVER, + MSAF_M5_SERVER, + MSAF_MAF_MGMT_SERVER, + +} msaf_server_type_e; + typedef struct msaf_application_server_state_node_s msaf_application_server_state_node_t; typedef struct purge_resource_id_node_s purge_resource_id_node_t; @@ -42,6 +47,7 @@ typedef struct msaf_event_s { int local_id; msaf_application_server_state_node_t *application_server_state; purge_resource_id_node_t *purge_node; + ogs_sbi_message_t *message; ogs_pkbuf_t *pkbuf; @@ -58,7 +64,7 @@ typedef struct msaf_event_s { OGS_STATIC_ASSERT(OGS_EVENT_SIZE >= sizeof(msaf_event_t)); extern const char *msaf_event_get_name(msaf_event_t *e); -extern int get_server_type_from_event(msaf_event_t *e); +extern int check_event_addresses(msaf_event_t *e, ogs_sockaddr_t *sockaddr_v4, ogs_sockaddr_t *sockaddr_v6); #ifdef __cplusplus diff --git a/src/5gmsaf/generator-5gmsaf b/src/5gmsaf/generator-5gmsaf index 3c4fe8d..e116c46 100755 --- a/src/5gmsaf/generator-5gmsaf +++ b/src/5gmsaf/generator-5gmsaf @@ -29,7 +29,7 @@ scriptdir=`cd "$scriptdir"; pwd` # Command line option defaults default_branch='REL-17' -default_apis="TS26512_M1_ProvisioningSessions TS26512_M1_ContentHostingProvisioning TS26512_M1_ServerCertificatesProvisioning TS26512_M1_ContentProtocolsDiscovery M3_ContentHostingProvisioning M3_ServerCertificatesProvisioning TS26512_M5_ServiceAccessInformation" +default_apis="TS26512_M1_ProvisioningSessions TS26512_M1_ContentHostingProvisioning TS26512_M1_ServerCertificatesProvisioning TS26512_M1_ContentProtocolsDiscovery M3_ContentHostingProvisioning M3_ServerCertificatesProvisioning TS26512_M5_ServiceAccessInformation Maf_Management" # Parse command line arguments ARGS=`getopt -n "$scriptname" -o 'a:b:h' -l 'api:,branch:,help' -s sh -- "$@"` diff --git a/src/5gmsaf/init.c b/src/5gmsaf/init.c index da8a8e6..60ca878 100644 --- a/src/5gmsaf/init.c +++ b/src/5gmsaf/init.c @@ -10,15 +10,13 @@ program. If this file is missing then the license can be retrieved from #include "context.h" #include "sbi-path.h" -#include "msaf-mgmt-sm.h" #include "init.h" static ogs_thread_t *thread; -static void msaf_main(void *data); +static void msaf_main(void *data); static int msaf_set_time(void); - static int initialized = 0; int msaf_initialize() @@ -45,8 +43,7 @@ int msaf_initialize() return OGS_ERROR; } - rv = ogs_log_config_domain( - ogs_app()->logger.domain, ogs_app()->logger.level); + rv = ogs_log_config_domain(ogs_app()->logger.domain, ogs_app()->logger.level); if (rv != OGS_OK) return rv; rv = msaf_sbi_open(); @@ -95,11 +92,20 @@ void msaf_terminate(void) static void msaf_main(void *data) { ogs_fsm_t msaf_sm; - ogs_fsm_t msaf_mgmt_sm; int rv; ogs_fsm_init(&msaf_sm, msaf_state_initial, msaf_state_final, 0); - ogs_fsm_init(&msaf_mgmt_sm, msaf_mgmt_state_initial, msaf_mgmt_state_final, 0); + + /* + ogs_fsm_init(&msaf_self()->msaf_fsm.msaf_m1_sm, msaf_m1_state_initial, msaf_m1_state_final, 0); + ogs_fsm_init(&msaf_self()->msaf_fsm.msaf_m5_sm, msaf_m5_state_initial, msaf_m5_state_final, 0); + if(msaf_self()->config.sbi_server_sockaddr || msaf_self()->config.sbi_server_sockaddr_v6) { + ogs_fsm_init(&msaf_self()->msaf_fsm.msaf_sbi_sm, msaf_sbi_state_initial, msaf_sbi_state_final, 0); + } + if(msaf_self()->config.maf_mgmt_server_sockaddr || msaf_self()->config.maf_mgmt_server_sockaddr_v6) { + ogs_fsm_init(&msaf_self()->msaf_fsm.msaf_maf_mgmt_sm, msaf_maf_mgmt_state_initial, msaf_maf_mgmt_state_final, 0); + } + */ for ( ;; ) { ogs_pollset_poll(ogs_app()->pollset, @@ -120,22 +126,30 @@ static void msaf_main(void *data) break; ogs_assert(e); + + ogs_fsm_dispatch(&msaf_sm, e); + /* rv = get_server_type_from_event(e); - if (rv == MSAF_APP_SERVER) { - ogs_fsm_dispatch(&msaf_sm, e); + if (rv == MSAF_M1_SERVER) { + ogs_fsm_dispatch(&msaf_self()->msaf_fsm.msaf_m1_sm, e); + } + if (rv == MSAF_M5_SERVER) { + ogs_fsm_dispatch(&msaf_self()->msaf_fsm.msaf_m5_sm, e); } - if(rv == MSAF_MGMT_SERVER) { - ogs_fsm_dispatch(&msaf_mgmt_sm, e); + if(rv == MSAF_MAF_MGMT_SERVER) { + ogs_fsm_dispatch(&msaf_self()->msaf_fsm.msaf_maf_mgmt_sm, e); + } + if (rv == MSAF_SBI_SERVER) { + ogs_fsm_dispatch(&msaf_self()->msaf_fsm.msaf_sbi_sm, e); } + */ ogs_event_free(e); } } done: - + ogs_fsm_fini(&msaf_sm, 0); - if(msaf_self()->config.mgmt_server_sockaddr || msaf_self()->config.mgmt_server_sockaddr_v6) { - ogs_fsm_fini(&msaf_mgmt_sm, 0); - } + } static int msaf_set_time(void) diff --git a/src/5gmsaf/meson.build b/src/5gmsaf/meson.build index cb1fa70..bd3657f 100644 --- a/src/5gmsaf/meson.build +++ b/src/5gmsaf/meson.build @@ -44,10 +44,13 @@ libmsaf_dist_sources = files(''' sbi-path.h service-access-information.h service-access-information.c - msaf-mgmt-sm.c - msaf-mgmt-sm.h - msaf-sm.c + msaf-fsm.h + msaf-fsm.c msaf-sm.h + msaf-sm.c + msaf-mgmt-sm.c + msaf-m1-sm.c + msaf-m5-sm.c utilities.h utilities.c init.c diff --git a/src/5gmsaf/msaf-fsm.c b/src/5gmsaf/msaf-fsm.c new file mode 100644 index 0000000..29d909e --- /dev/null +++ b/src/5gmsaf/msaf-fsm.c @@ -0,0 +1,30 @@ +/* +License: 5G-MAG Public License (v1.0) +Author: Dev Audsin +Copyright: (C) 2022 British Broadcasting Corporation + +For full license terms please see the LICENSE file distributed with this +program. If this file is missing then the license can be retrieved from +https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +*/ + +#include "msaf-sm.h" +#include "msaf-fsm.h" + +void msaf_fsm_init(void) { + + ogs_fsm_init(&msaf_self()->msaf_fsm.msaf_m1_sm, msaf_m1_state_initial, msaf_m1_state_final, 0); + ogs_fsm_init(&msaf_self()->msaf_fsm.msaf_m5_sm, msaf_m5_state_initial, msaf_m5_state_final, 0); + if(msaf_self()->config.maf_mgmt_server_sockaddr || msaf_self()->config.maf_mgmt_server_sockaddr_v6) { + ogs_fsm_init(&msaf_self()->msaf_fsm.msaf_maf_mgmt_sm, msaf_maf_mgmt_state_initial, msaf_maf_mgmt_state_final, 0); + } + +} + +void msaf_fsm_fini(void) { + ogs_fsm_fini(&msaf_self()->msaf_fsm.msaf_m1_sm, 0); + ogs_fsm_fini(&msaf_self()->msaf_fsm.msaf_m5_sm, 0); + if(msaf_self()->config.maf_mgmt_server_sockaddr || msaf_self()->config.maf_mgmt_server_sockaddr_v6) { + ogs_fsm_fini(&msaf_self()->msaf_fsm.msaf_maf_mgmt_sm, 0); + } +} diff --git a/src/5gmsaf/msaf-fsm.h b/src/5gmsaf/msaf-fsm.h new file mode 100644 index 0000000..ae7441e --- /dev/null +++ b/src/5gmsaf/msaf-fsm.h @@ -0,0 +1,34 @@ +/* +License: 5G-MAG Public License (v1.0) +Copyright: (C) 2022 British Broadcasting Corporation + +For full license terms please see the LICENSE file distributed with this +program. If this file is missing then the license can be retrieved from +https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +*/ + +#ifndef MSAF_FSM_H +#define MSAF_FSM_H + +#include "ogs-app.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct msaf_fsm_s { + ogs_fsm_t msaf_sbi_sm; + ogs_fsm_t msaf_m1_sm; + ogs_fsm_t msaf_m5_sm; + ogs_fsm_t msaf_maf_mgmt_sm; +} msaf_fsm_t; + +extern void msaf_fsm_init(void); +extern void msaf_fsm_fini(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* MSAF_FSM_H */ diff --git a/src/5gmsaf/msaf-m1-sm.c b/src/5gmsaf/msaf-m1-sm.c new file mode 100644 index 0000000..a64d202 --- /dev/null +++ b/src/5gmsaf/msaf-m1-sm.c @@ -0,0 +1,1833 @@ +/* + * License: 5G-MAG Public License (v1.0) + * Author: Dev Audsin + * Copyright: (C) 2022 British Broadcasting Corporation + * + * For full license terms please see the LICENSE file distributed with this + * program. If this file is missing then the license can be retrieved from + * https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view + */ + + +#include "ogs-sbi.h" +#include "sbi-path.h" +#include "context.h" +#include "certmgr.h" +#include "server.h" +#include "response-cache-control.h" +#include "msaf-version.h" +#include "msaf-sm.h" +#include "ContentProtocolsDiscovery_body.h" +#include "openapi/api/TS26512_M1_ProvisioningSessionsAPI-info.h" +#include "openapi/api/TS26512_M1_ServerCertificatesProvisioningAPI-info.h" +#include "openapi/api/TS26512_M1_ContentHostingProvisioningAPI-info.h" +#include "openapi/api/M3_ServerCertificatesProvisioningAPI-info.h" +#include "openapi/api/M3_ContentHostingProvisioningAPI-info.h" +#include "openapi/api/TS26512_M1_ContentProtocolsDiscoveryAPI-info.h" +#include "openapi/api/Maf_ManagementAPI-info.h" + +const nf_server_interface_metadata_t +m1_provisioningsession_api_metadata = { + M1_PROVISIONINGSESSIONS_API_NAME, + M1_PROVISIONINGSESSIONS_API_VERSION +}; + +const nf_server_interface_metadata_t +m1_contenthostingprovisioning_api_metadata = { + M1_CONTENTHOSTINGPROVISIONING_API_NAME, + M1_CONTENTHOSTINGPROVISIONING_API_VERSION +}; + +const nf_server_interface_metadata_t +m1_contentprotocolsdiscovery_api_metadata = { + M1_CONTENTPROTOCOLSDISCOVERY_API_NAME, + M1_CONTENTPROTOCOLSDISCOVERY_API_VERSION +}; + +const nf_server_interface_metadata_t +m1_servercertificatesprovisioning_api_metadata = { + M1_SERVERCERTIFICATESPROVISIONING_API_NAME, + M1_SERVERCERTIFICATESPROVISIONING_API_VERSION +}; + +const nf_server_interface_metadata_t +m3_contenthostingprovisioning_api_metatdata = { + M3_CONTENTHOSTINGPROVISIONING_API_NAME, + M3_CONTENTHOSTINGPROVISIONING_API_VERSION +}; + +const nf_server_interface_metadata_t +maf_management_api_metadata = { + MAF_MANAGEMENT_API_NAME, + MAF_MANAGEMENT_API_VERSION +}; + +void msaf_m1_state_initial(ogs_fsm_t *s, msaf_event_t *e) +{ + msaf_sm_debug(e); + + ogs_assert(s); + + OGS_FSM_TRAN(s, &msaf_m1_state_functional); +} + +void msaf_m1_state_final(ogs_fsm_t *s, msaf_event_t *e) +{ + msaf_sm_debug(e); + + ogs_assert(s); +} + +void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) +{ + int rv; + + ogs_sbi_stream_t *stream = NULL; + ogs_sbi_request_t *request = NULL; + + ogs_sbi_nf_instance_t *nf_instance = NULL; + ogs_sbi_subscription_data_t *subscription_data = NULL; + ogs_sbi_response_t *response = NULL; + ogs_sbi_message_t message; + ogs_sbi_xact_t *sbi_xact = NULL; + + msaf_sm_debug(e); + + char *nf_name = ogs_msprintf("5GMSdAF-%s", msaf_self()->server_name); + const nf_server_app_metadata_t app_metadata = { MSAF_NAME, MSAF_VERSION, nf_name}; + const nf_server_interface_metadata_t *m1_provisioningsession_api = &m1_provisioningsession_api_metadata; + const nf_server_interface_metadata_t *m1_contenthostingprovisioning_api = &m1_contenthostingprovisioning_api_metadata; + const nf_server_interface_metadata_t *m1_contentprotocolsdiscovery_api = &m1_contentprotocolsdiscovery_api_metadata; + const nf_server_interface_metadata_t *m1_servercertificatesprovisioning_api = &m1_servercertificatesprovisioning_api_metadata; + const nf_server_interface_metadata_t *m3_contenthostingprovisioning_api = &m3_contenthostingprovisioning_api_metatdata; + const nf_server_interface_metadata_t *maf_management_api = &maf_management_api_metadata; + const nf_server_app_metadata_t *app_meta = &app_metadata; + + ogs_assert(s); + + switch (e->h.id) { + case OGS_FSM_ENTRY_SIG: + ogs_info("[%s] MSAF M1 Running", ogs_sbi_self()->nf_instance->id); + + break; + + case OGS_FSM_EXIT_SIG: + break; + + case OGS_EVENT_SBI_SERVER: + request = e->h.sbi.request; + ogs_assert(request); + stream = e->h.sbi.data; + ogs_assert(stream); + message = *(e->message); + + SWITCH(message.h.service.name) + CASE("3gpp-m1") + if (strcmp(message.h.api.version, "v2") != 0) { + char *error; + ogs_error("Not supported version [%s]", message.h.api.version); + + error = ogs_msprintf("Version [%s] not supported", message.h.api.version); + + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL, app_meta)); + + ogs_sbi_message_free(&message); + ogs_free(error); + break; + } + SWITCH(message.h.resource.component[0]) + + CASE("provisioning-sessions") + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) + + if (message.h.resource.component[1] && message.h.resource.component[2] && message.h.resource.component[3]) { + msaf_provisioning_session_t *msaf_provisioning_session; + + if (!strcmp(message.h.resource.component[2],"content-hosting-configuration") && !strcmp(message.h.resource.component[3],"purge")) { + ogs_hash_index_t *hi; + for (hi = ogs_hash_first(request->http.headers); + hi; hi = ogs_hash_next(hi)) { + if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { + if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/x-www-form-urlencoded")) { + char *err = NULL; + char *type = NULL; + type = (char *)ogs_hash_this_val(hi); + ogs_error("Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); + asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); + + ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + ogs_sbi_message_free(&message); + return; + + } + } + } + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if(msaf_provisioning_session) { + // process the POST body + purge_resource_id_node_t *purge_cache; + msaf_application_server_state_node_t *as_state; + assigned_provisioning_sessions_node_t *assigned_provisioning_sessions_resource; + m1_purge_information_t *m1_purge_info = ogs_calloc(1, sizeof(m1_purge_information_t)); + m1_purge_info->m1_stream = stream; + m1_purge_info->m1_message = message; + + ogs_list_for_each(&msaf_provisioning_session->msaf_application_server_state_nodes, as_state) { + if(as_state->application_server && as_state->application_server->canonicalHostname) { + ogs_list_for_each(&as_state->assigned_provisioning_sessions,assigned_provisioning_sessions_resource){ + if(!strcmp(assigned_provisioning_sessions_resource->assigned_provisioning_session->provisioningSessionId, msaf_provisioning_session->provisioningSessionId)) { + + purge_cache = ogs_calloc(1, sizeof(purge_resource_id_node_t)); + ogs_assert(purge_cache); + purge_cache->provisioning_session_id = ogs_strdup(assigned_provisioning_sessions_resource->assigned_provisioning_session->provisioningSessionId); + + purge_cache->m1_purge_info = m1_purge_info; + m1_purge_info->refs++; + if(request->http.content) + purge_cache->purge_regex = ogs_strdup(request->http.content); + else + purge_cache->purge_regex = NULL; + + if (ogs_list_first(&as_state->purge_content_hosting_cache) == NULL) + ogs_list_init(&as_state->purge_content_hosting_cache); + + ogs_list_add(&as_state->purge_content_hosting_cache, purge_cache); + } else { + ogs_error("Provisioning Session [%s] is not assigned to an Application Server", message.h.resource.component[1]); + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] is not assigned to an Application Server", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session is not assigned to an Application Server.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + } + } + } else { + ogs_error("Provisioning Session [%s]: Unable to get information about Application Server", message.h.resource.component[1]); + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] : Unable to get information about Application Server", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Unable to get information about Application Server", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + } + + next_action_for_application_server(as_state); + } + if (m1_purge_info->refs == 0) { + ogs_free(m1_purge_info); + // Send 204 back to M1 client + ogs_sbi_response_t *response; + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_contenthostingprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + } + } else { + ogs_error("Unable to retrieve the Provisioning Session [%s]", message.h.resource.component[1]); + char *err = NULL; + asprintf(&err,"Provisioning session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + + } + + } + + } else if (message.h.resource.component[1] && message.h.resource.component[2]) { + msaf_provisioning_session_t *msaf_provisioning_session; + if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if(msaf_provisioning_session) { + // process the POST body + cJSON *entry; + int rv; + cJSON *chc; + cJSON *content_hosting_config = cJSON_Parse(request->http.content); + char *txt = cJSON_Print(content_hosting_config); + ogs_debug("body:%s", request->http.content); + ogs_debug("txt:%s", txt); + + cJSON_ArrayForEach(entry, content_hosting_config) { + if(!strcmp(entry->string, "entryPointPath")){ + if(!uri_relative_check(entry->valuestring)) { + char *err = NULL; + asprintf(&err,"While creating the Content Hosting Configuration for the Provisioning Session [%s], entryPointPath does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring ); + ogs_error("While creating the Content Hosting Configuration for the Provisioning Session [%s], entryPointPath does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring); + + ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + + cJSON_Delete(content_hosting_config); + break; + } + } + } + + if(msaf_provisioning_session->contentHostingConfiguration) { + OpenAPI_content_hosting_configuration_free(msaf_provisioning_session->contentHostingConfiguration); + msaf_provisioning_session->contentHostingConfiguration = NULL; + + } + + if (msaf_provisioning_session->serviceAccessInformation) { + OpenAPI_service_access_information_resource_free(msaf_provisioning_session->serviceAccessInformation); + msaf_provisioning_session->serviceAccessInformation = NULL; + } + + rv = msaf_distribution_create(content_hosting_config, msaf_provisioning_session); + + if(rv){ + + ogs_debug("Content Hosting Configuration created successfully"); + if (msaf_application_server_state_set_on_post(msaf_provisioning_session)) { + chc = msaf_get_content_hosting_configuration_by_provisioning_session_id(message.h.resource.component[1]); + if (chc != NULL) { + char *text; + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, NULL, m1_contentprotocolsdiscovery_api, app_meta); + text = cJSON_Print(chc); + nf_server_populate_response(response, strlen(text), text, 201); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + cJSON_Delete(chc); + cJSON_Delete(content_hosting_config); + } else { + char *err = NULL; + ogs_error("Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); + asprintf(&err,"Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + } + } else { + char *err = NULL; + ogs_error("Verification error on Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); + asprintf(&err,"Verification error on Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 400, 2, &message, "Bad Content Hosting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + } + } else { + char *err = NULL; + + ogs_error("Failed to populate Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); + asprintf(&err,"Creation of the Content Hosting Configuration failed for the Provisioning Session [%s]", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 500, 2, &message, "Creation of the Content Hosting Configuration failed.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + } + + } else { + char *err = NULL; + asprintf(&err,"Provisioning session [%s]does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + + + } + + } + if (!strcmp(message.h.resource.component[2],"certificates")) { + ogs_info("POST certificates"); + ogs_hash_index_t *hi; + char *canonical_domain_name; + char *cert; + int csr = 0; + + for (hi = ogs_hash_first(request->http.params); + hi; hi = ogs_hash_next(hi)) { + if (!ogs_strcasecmp(ogs_hash_this_key(hi), "csr")) { + csr = 1; + break; + } + } + + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if (msaf_provisioning_session) { + msaf_application_server_node_t *msaf_as = NULL; + msaf_as = ogs_list_first(&msaf_self()->config.applicationServers_list); + canonical_domain_name = msaf_as->canonicalHostname; + ogs_info("canonical_domain_name: %s", canonical_domain_name); + + if (csr) { + msaf_certificate_t *csr_cert; + char *location; + int m1_server_certificates_response_max_age; + csr_cert = server_cert_new("newcsr", canonical_domain_name); + ogs_hash_set(msaf_provisioning_session->certificate_map, ogs_strdup(csr_cert->id), OGS_HASH_KEY_STRING, ogs_strdup(csr_cert->id)); + ogs_sbi_response_t *response; + location = ogs_msprintf("%s/%s", request->h.uri, csr_cert->id); + if(csr_cert->cache_control_max_age){ + m1_server_certificates_response_max_age = csr_cert->cache_control_max_age; + } else { + m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; + } + response = nf_server_new_response(location, "application/x-pem-file", csr_cert->last_modified, csr_cert->server_certificate_hash, m1_server_certificates_response_max_age, NULL, m1_servercertificatesprovisioning_api, app_meta); + + nf_server_populate_response(response, strlen(csr_cert->certificate), ogs_strdup(csr_cert->certificate), 200); + + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + ogs_free(location); + msaf_certificate_free(csr_cert); + + return; + } + + if (ogs_list_first(&msaf_provisioning_session->msaf_application_servers) == NULL) { + ogs_list_init(&msaf_provisioning_session->msaf_application_server_state_nodes); + ogs_list_add(&msaf_provisioning_session->msaf_application_server_state_nodes, msaf_as); + } + + cert = check_in_cert_list(canonical_domain_name); + if (cert != NULL) { + ogs_sbi_response_t *response; + char *location; + + ogs_hash_set(msaf_provisioning_session->certificate_map, ogs_strdup(cert), OGS_HASH_KEY_STRING, ogs_strdup(cert)); + + location = ogs_msprintf("%s/%s", request->h.uri, cert); + response = nf_server_new_response(location, NULL, 0, NULL, 0, NULL, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 200); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + ogs_free(location); + } else { + msaf_certificate_t *new_cert; + int m1_server_certificates_response_max_age; + ogs_sbi_response_t *response; + char *location; + new_cert = server_cert_new("newcert", canonical_domain_name); + ogs_hash_set(msaf_provisioning_session->certificate_map, ogs_strdup(new_cert->id), OGS_HASH_KEY_STRING, ogs_strdup(new_cert->id)); + + location = ogs_msprintf("%s/%s", request->h.uri, new_cert->id); + if(new_cert->cache_control_max_age){ + m1_server_certificates_response_max_age = new_cert->cache_control_max_age; + } else { + m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; + } + response = nf_server_new_response(location, NULL, new_cert->last_modified, new_cert->server_certificate_hash, m1_server_certificates_response_max_age, NULL, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 200); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + ogs_free(location); + msaf_certificate_free(new_cert); + } + } else { + char *err = NULL; + asprintf(&err,"Provisioning session [%s] does not exists.", message.h.resource.component[1]); + ogs_error("Provisioning session [%s] does not exists.", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + } + } + + } else if (message.h.resource.component[1]){ + msaf_provisioning_session_t *msaf_provisioning_session; + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if(msaf_provisioning_session) { + ogs_error("Method [%s] not allowed for [%s]", message.h.method, message.h.resource.component[1]); + char *err = NULL; + asprintf(&err,"Method [%s] not allowed for [%s].", message.h.method, message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 405, 1, &message, "Method not allowed.", err, NULL, m1_provisioningsession_api, app_meta)); + + } else { + char *err = NULL; + asprintf(&err,"Provisioning session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Provisioning session does not exist.", err, NULL, m1_provisioningsession_api, app_meta)); + } + + } else { + cJSON *entry; + cJSON *prov_sess = cJSON_Parse(request->http.content); + cJSON *provisioning_session; + char *provisioning_session_type, *external_app_id, *asp_id = NULL; + msaf_provisioning_session_t *msaf_provisioning_session; + + cJSON_ArrayForEach(entry, prov_sess) { + if(!strcmp(entry->string, "provisioningSessionType")){ + provisioning_session_type = entry->valuestring; + } + if(!strcmp(entry->string, "aspId")){ + asp_id = entry->valuestring; + } + if(!strcmp(entry->string, "externalApplicationId")){ + external_app_id = entry->valuestring; + } + } + msaf_provisioning_session = msaf_provisioning_session_create(provisioning_session_type, asp_id, external_app_id); + provisioning_session = msaf_provisioning_session_get_json(msaf_provisioning_session->provisioningSessionId); + if (provisioning_session != NULL) { + ogs_sbi_response_t *response; + char *text; + char *location; + text = cJSON_Print(provisioning_session); + if (request->h.uri[strlen(request->h.uri)-1] != '/') { + location = ogs_msprintf("%s/%s", request->h.uri,msaf_provisioning_session->provisioningSessionId); + } else { + location = ogs_msprintf("%s%s", request->h.uri,msaf_provisioning_session->provisioningSessionId); + } + response = nf_server_new_response(location, "application/json", msaf_provisioning_session->provisioningSessionReceived, msaf_provisioning_session->provisioningSessionHash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, m1_provisioningsession_api, app_meta); + + nf_server_populate_response(response, strlen(text), text, 201); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + ogs_free(location); + cJSON_Delete(provisioning_session); + cJSON_Delete(prov_sess); + } else { + char *err = NULL; + asprintf(&err,"Creation of the Provisioning session failed."); + ogs_error("Creation of the Provisioning session failed."); + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); + } + } + + break; + + CASE(OGS_SBI_HTTP_METHOD_GET) + if (message.h.resource.component[1] && message.h.resource.component[2] && message.h.resource.component[3]) { + if (!strcmp(message.h.resource.component[2],"certificates") ) { + msaf_provisioning_session_t *msaf_provisioning_session; + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if (msaf_provisioning_session) { + msaf_certificate_t *cert; + ogs_sbi_response_t *response; + const char *provisioning_session_cert; + provisioning_session_cert = ogs_hash_get(msaf_provisioning_session->certificate_map, message.h.resource.component[3], OGS_HASH_KEY_STRING); + cert = server_cert_retrieve(message.h.resource.component[3]); + if(!cert || !provisioning_session_cert) { + ogs_error("unable to retrieve certificate [%s]", message.h.resource.component[3]); + char *err = NULL; + asprintf(&err,"Unable to retrieve Certificate not yet available"); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate not yet available.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + return; + } + + if(!cert->return_code) { + int m1_server_certificates_response_max_age; + if(cert->cache_control_max_age){ + m1_server_certificates_response_max_age = cert->cache_control_max_age; + } else { + m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; + } + response = nf_server_new_response(NULL, "application/x-pem-file", cert->last_modified, cert->server_certificate_hash, m1_server_certificates_response_max_age, NULL, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, strlen(cert->certificate), ogs_strdup(cert->certificate), 200); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + } else if(cert->return_code == 4){ + char *err = NULL; + asprintf(&err,"Certificate [%s] does not exists.", cert->id); + ogs_error("Certificate [%s] does not exists.", cert->id); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + + } else if(cert->return_code == 8){ + char *err = NULL; + asprintf(&err,"Certificate [%s] not yet available.", cert->id); + ogs_error("Certificate [%s] not yet available.", cert->id); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate not yet available.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + } else { + char *err = NULL; + asprintf(&err,"Certificate [%s] management problem.", cert->id); + ogs_error("Certificate [%s] management problem.", cert->id); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + } + msaf_certificate_free(cert); + + } else { + char *err = NULL; + asprintf(&err,"Provisioning session [%s] is not available.", message.h.resource.component[1]); + ogs_error("Provisioning session [%s] is not available.", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + } + } + } else if (message.h.resource.component[1] && message.h.resource.component[2]) { + msaf_provisioning_session_t *msaf_provisioning_session; + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { + if(msaf_provisioning_session) { + cJSON *chc; + chc = msaf_get_content_hosting_configuration_by_provisioning_session_id(message.h.resource.component[1]); + if (chc != NULL) { + ogs_sbi_response_t *response; + char *text; + text = cJSON_Print(chc); + + response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, NULL, m1_contenthostingprovisioning_api, app_meta); + ogs_assert(response); + nf_server_populate_response(response, strlen(text), text, 200); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + + cJSON_Delete(chc); + } else { + char *err = NULL; + ogs_error("Provisioning Session [%s]: Unable to retrieve the Content Hosting Configuration", message.h.resource.component[1]); + asprintf(&err,"Provisioning Session [%s]: Unable to retrieve the Content Hosting Configuration", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + } + + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + + } + + } else if (!strcmp(message.h.resource.component[2],"protocols")) { + if(msaf_provisioning_session) { + ogs_sbi_response_t *response; + ogs_info("CONTENT_PROTOCOLS_DISCOVERY_JSON: %s", CONTENT_PROTOCOLS_DISCOVERY_JSON); + response = nf_server_new_response(NULL, "application/json", CONTENT_PROTOCOLS_DISCOVERY_JSON_TIME, CONTENT_PROTOCOLS_DISCOVERY_JSON_HASH, msaf_self()->config.server_response_cache_control->m1_content_protocols_response_max_age, NULL, m1_contentprotocolsdiscovery_api, app_meta); + ogs_assert(response); + nf_server_populate_response(response, strlen(CONTENT_PROTOCOLS_DISCOVERY_JSON), ogs_strdup(CONTENT_PROTOCOLS_DISCOVERY_JSON), 200); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contentprotocolsdiscovery_api, app_meta)); + } + } + } else if (message.h.resource.component[1]) { + msaf_provisioning_session_t *msaf_provisioning_session = NULL; + cJSON *provisioning_session = NULL; + + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + + provisioning_session = msaf_provisioning_session_get_json(message.h.resource.component[1]); + + if (provisioning_session && msaf_provisioning_session && !msaf_provisioning_session->marked_for_deletion) { + ogs_sbi_response_t *response; + char *text; + text = cJSON_Print(provisioning_session); + + response = nf_server_new_response(NULL, "application/json", msaf_provisioning_session->provisioningSessionReceived, msaf_provisioning_session->provisioningSessionHash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, m1_provisioningsession_api, app_meta); + + nf_server_populate_response(response, strlen(text), text, 200); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + cJSON_Delete(provisioning_session); + + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] is not available.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] is not available.", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL, m1_provisioningsession_api, app_meta)); + } + } + break; + + CASE(OGS_SBI_HTTP_METHOD_PUT) + if (message.h.resource.component[1] && message.h.resource.component[2]) { + + ogs_info("PUT: %s", message.h.resource.component[1]); + msaf_provisioning_session_t *msaf_provisioning_session; + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if(msaf_provisioning_session) { + ogs_info("PUT: with msaf_provisioning_session: %s", message.h.resource.component[1]); + if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { + + // process the POST body + cJSON *entry; + int rv; + cJSON *content_hosting_config = cJSON_Parse(request->http.content); + char *txt = cJSON_Print(content_hosting_config); + ogs_debug("txt:%s", txt); + + cJSON_ArrayForEach(entry, content_hosting_config) { + if(!strcmp(entry->string, "entryPointPath")){ + if(!uri_relative_check(entry->valuestring)) { + char *err = NULL; + asprintf(&err,"While updating the Content Hosting Configuration for the Provisioning Session [%s], Entry Point Path does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring ); + ogs_error("While updating the Content Hosting Configuration for the provisioning Session [%s], Entry Point Path does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring); + + ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + + cJSON_Delete(content_hosting_config); + break; + } + } + } + if(msaf_provisioning_session->contentHostingConfiguration) { + OpenAPI_content_hosting_configuration_free(msaf_provisioning_session->contentHostingConfiguration); + msaf_provisioning_session->contentHostingConfiguration = NULL; + } + + if (msaf_provisioning_session->serviceAccessInformation) { + OpenAPI_service_access_information_resource_free(msaf_provisioning_session->serviceAccessInformation); + msaf_provisioning_session->serviceAccessInformation = NULL; + } + + rv = msaf_distribution_create(content_hosting_config, msaf_provisioning_session); + if(rv){ + + msaf_application_server_state_update(msaf_provisioning_session); + + ogs_debug("Content Hosting Configuration updated successfully"); + + ogs_sbi_response_t *response; + response = ogs_sbi_response_new(); + response->status = 204; + ogs_sbi_header_set(response->http.headers, "Content-Type", "application/json"); + ogs_sbi_header_set(response->http.headers, "Location", request->h.uri); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + cJSON_Delete(content_hosting_config); + + } else { + char *err = NULL; + ogs_error("Provisioning Session [%s]: Failed to update the Content Hosting Configuration.", message.h.resource.component[1]); + asprintf(&err,"Provisioning Session [%s]: Update to Content Hosting Configuration failed.", message.h.resource.component[1]); + ogs_error("Update of the Content Hosting Configuration failed."); + + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Failed to update the contentHostingConfiguration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + + } + } + if (message.h.resource.component[1] && !strcmp(message.h.resource.component[2],"certificates") && message.h.resource.component[3]) { + char *cert_id; + char *cert; + int rv; + ogs_sbi_response_t *response; + msaf_provisioning_session_t *msaf_provisioning_session; + + { + ogs_hash_index_t *hi; + for (hi = ogs_hash_first(request->http.headers); + hi; hi = ogs_hash_next(hi)) { + if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { + if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/x-pem-file")) { + char *err = NULL; + char *type = NULL; + type = (char *)ogs_hash_this_val(hi); + ogs_error("Unsupported Media Type: received type: %s, should have been application/x-pem-file", type); + asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-pem-file", type); + + ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + ogs_sbi_message_free(&message); + return; + + } + } + } + } + + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + + if(msaf_provisioning_session) { + const char *provisioning_session_cert; + provisioning_session_cert = ogs_hash_get(msaf_provisioning_session->certificate_map, message.h.resource.component[3], OGS_HASH_KEY_STRING); + cert_id = message.h.resource.component[3]; + cert = ogs_strdup(request->http.content); + rv = server_cert_set(cert_id, cert); + // response = ogs_sbi_response_new(); + + if (rv == 0 && provisioning_session_cert){ + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + } else if (rv == 3 && provisioning_session_cert ) { + + char *err = NULL; + ogs_error("A server certificate with id [%s] already exist", cert_id); + asprintf(&err,"A server certificate with id [%s] already exist", cert_id); + ogs_assert(true == nf_server_send_error(stream, 403, 3, &message, "A server certificate already exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + + } else if(rv == 4 || ! provisioning_session_cert) { + char *err = NULL; + ogs_error("Server certificate with id [%s] does not exist", cert_id); + asprintf(&err,"Server certificate with id [%s] does not exist", cert_id); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Server certificate does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + + } else if(rv == 5) { + char *err = NULL; + ogs_error("CSR was never generated for this certificate Id [%s]", cert_id); + asprintf(&err,"CSR was never generated for this certificate Id [%s]", cert_id); + ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "CSR was never generated for the certificate.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + } else if(rv == 6) { + char *err = NULL; + ogs_error("The public certificate [%s] provided does not match the key", cert_id); + asprintf(&err,"The public certificate [%s] provided does not match the key", cert_id); + ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "The public certificate provided does not match the key.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + } else { + char *err = NULL; + ogs_error("There was a certificate management problem for the certificate id [%s]", cert_id); + asprintf(&err,"There was a certificate management problem for the certificate id [%s].", cert_id); + + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "There was a certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + + + } + ogs_free(cert); + } + + } + + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + + } + + + } else { + char *err = NULL; + asprintf(&err,"[%s]: Resource not found.", message.h.method); + ogs_error("[%s]: Resource not found.", message.h.method); + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Resource not found.", err, NULL, m1_provisioningsession_api, app_meta)); + } + break; + + CASE(OGS_SBI_HTTP_METHOD_DELETE) + + if (message.h.resource.component[1] && !strcmp(message.h.resource.component[2],"certificates") && message.h.resource.component[3]) { + ogs_sbi_response_t *response; + msaf_provisioning_session_t *provisioning_session = NULL; + provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if (provisioning_session) { + int rv; + rv = server_cert_delete(message.h.resource.component[3]); + if ((rv == 0) || (rv == 8)){ + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + msaf_provisioning_session_certificate_hash_remove(message.h.resource.component[1], message.h.resource.component[3]); + + } else if (rv == 4 ) { + char *err = NULL; + asprintf(&err,"Certificate [%s] does not exist.", message.h.resource.component[3]); + ogs_error("Certificate [%s] does not exist.", message.h.resource.component[3]); + + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + + } else { + char *err = NULL; + asprintf(&err,"Certificate management problem for certificate [%s].", message.h.resource.component[3]); + ogs_error("Certificate management problem."); + + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + } + + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + + + } + } else if (message.h.resource.component[1] && message.h.resource.component[2]) { + msaf_provisioning_session_t *msaf_provisioning_session; + ogs_sbi_response_t *response; + if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if(msaf_provisioning_session){ + if(msaf_provisioning_session && msaf_provisioning_session->contentHostingConfiguration) { + msaf_delete_content_hosting_configuration(message.h.resource.component[1]); + OpenAPI_content_hosting_configuration_free(msaf_provisioning_session->contentHostingConfiguration); + msaf_provisioning_session->contentHostingConfiguration = NULL; + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_contenthostingprovisioning_api, app_meta); + ogs_assert(response); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + break; + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] has no Content Hosting Configuration.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] has no Content Hosting Configuration.", message.h.resource.component[1] ); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Content Hosting Configuration does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + } + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] does not exists.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] does not exists.", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + } + + } + + } else if (message.h.resource.component[1]) { + ogs_sbi_response_t *response; + msaf_provisioning_session_t *provisioning_session = NULL; + provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if(!provisioning_session || provisioning_session->marked_for_deletion){ + char *err = NULL; + asprintf(&err,"Provisioning session [%s] either not found or already marked for deletion.", message.h.resource.component[1]); + + ogs_error("Provisioning session [%s] either not found or already marked for deletion.",message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session either not found or already marked for deletion.", err, NULL, m1_provisioningsession_api, app_meta)); + + } else { + provisioning_session->marked_for_deletion = 1; + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_provisioningsession_api, app_meta); + ogs_assert(response); + nf_server_populate_response(response, 0, NULL, 202); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + msaf_delete_content_hosting_configuration(message.h.resource.component[1]); + msaf_delete_certificate(message.h.resource.component[1]); + msaf_context_provisioning_session_free(provisioning_session); + msaf_provisioning_session_hash_remove(message.h.resource.component[1]); + } + } + + break; + CASE(OGS_SBI_HTTP_METHOD_OPTIONS) + + if (!strcmp(message.h.resource.component[0],"provisioning-sessions")){ + ogs_sbi_response_t *response; + char *methods = NULL; + + if (message.h.resource.component[1]) { + msaf_provisioning_session_t *provisioning_session = NULL; + provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + if (provisioning_session) { + if (message.h.resource.component[2]) { + + + if (!strcmp(message.h.resource.component[2],"certificates")) { + if (message.h.resource.component[3]) { + msaf_certificate_t *cert; + cert = server_cert_retrieve(message.h.resource.component[3]); + if(cert){ + methods = ogs_msprintf("%s, %s, %s, %s",OGS_SBI_HTTP_METHOD_GET, OGS_SBI_HTTP_METHOD_PUT, OGS_SBI_HTTP_METHOD_DELETE, OGS_SBI_HTTP_METHOD_OPTIONS); + response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + msaf_certificate_free(cert); + } else { + char *err = NULL; + ogs_error("Method [%s]: Unable to retrieve certificate [%s]", message.h.method, message.h.resource.component[3]); + asprintf(&err,"Method [%s]: Unable to retrieve certificate [%s]", message.h.method, message.h.resource.component[3]); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Unable to retrieve certificate.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + + } + } else { + methods = ogs_msprintf("%s",OGS_SBI_HTTP_METHOD_POST); + response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + } + + } else if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { + methods = ogs_msprintf("%s, %s, %s, %s, %s",OGS_SBI_HTTP_METHOD_POST, OGS_SBI_HTTP_METHOD_GET, OGS_SBI_HTTP_METHOD_PUT, OGS_SBI_HTTP_METHOD_DELETE, OGS_SBI_HTTP_METHOD_OPTIONS); + response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_contenthostingprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + + } else { + char *err = NULL; + asprintf(&err,"Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[2]); + ogs_error("Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[2]); + ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Target not yet supported.", err, NULL, NULL, app_meta)); + } + } else { + methods = ogs_msprintf("%s, %s, %s", OGS_SBI_HTTP_METHOD_GET, OGS_SBI_HTTP_METHOD_DELETE, OGS_SBI_HTTP_METHOD_OPTIONS); + response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_provisioningsession_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + + } + /* + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + + if(methods) ogs_free(methods); + */ + } else { + char *err = NULL; + int number_of_components; + const nf_server_interface_metadata_t *interface; + if (message.h.resource.component[2]){ + if (!strcmp(message.h.resource.component[2],"certificates")) { + number_of_components = 2; + if (message.h.resource.component[3]) { + number_of_components = 3; + } + interface = m1_servercertificatesprovisioning_api; + } else if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { + number_of_components = 2; + interface = m1_contenthostingprovisioning_api; + + } + } else if (message.h.resource.component[0]){ + if (!strcmp(message.h.resource.component[0],"provisioning-sessions")){ + number_of_components = 0; + if (message.h.resource.component[1]) { + number_of_components = 1; + } + interface = m1_provisioningsession_api; + + } + } + asprintf(&err,"Method [%s]: [%s] - Provisioning Session [%s] does not exist.", message.h.method, message.h.resource.component[2], message.h.resource.component[1]); + ogs_error("Method [%s]: [%s] - Provisioning Session [%s] does not exist.", message.h.method, message.h.resource.component[2], message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, number_of_components, &message, "Provisioning Session does not exists.", err, NULL, interface, app_meta)); + + } + + } else { + methods = ogs_msprintf("%s, %s",OGS_SBI_HTTP_METHOD_POST, OGS_SBI_HTTP_METHOD_OPTIONS); + response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_provisioningsession_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + + } + if(methods) ogs_free(methods); + } else { + char *err = NULL; + asprintf(&err,"Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[0]); + ogs_error("Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[0]); + ogs_assert(true == nf_server_send_error(stream, 404, 0, &message, "Target not yet supported.", err, NULL, m1_provisioningsession_api, app_meta)); + + } + break; + + DEFAULT + ogs_error("Invalid HTTP method [%s]", message.h.method); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 0, &message, "Invalid HTTP method.", message.h.method, NULL, NULL, app_meta)); + + END + break; + + DEFAULT + char *err; + ogs_error("Invalid resource name [%s]", + message.h.resource.component[0]); + asprintf(&err,"Invalid resource name [%s]", message.h.resource.component[0]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid resource name", err, NULL, NULL, app_meta)); + + END + ogs_sbi_message_free(&message); + break; + + CASE("5gmag-rt-management") + if (strcmp(message.h.api.version, "v1") != 0) { + char *error; + ogs_error("Not supported version [%s]", message.h.api.version); + + error = ogs_msprintf("Version [%s] not supported", message.h.api.version); + + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, maf_management_api, app_meta)); + + ogs_sbi_message_free(&message); + ogs_free(error); + break; + } + SWITCH(message.h.resource.component[0]) + + CASE("provisioning-sessions") + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_GET) + char *provisioning_sessions = NULL; + ogs_sbi_response_t *response; + provisioning_sessions = enumerate_provisioning_sessions(); + if(provisioning_sessions) { + response = nf_server_new_response(NULL, "application/json", 0, NULL, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, maf_management_api, app_meta); + + nf_server_populate_response(response, strlen(provisioning_sessions), ogs_strdup(provisioning_sessions), 200); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + if (strcmp(provisioning_sessions,"[]")) ogs_free(provisioning_sessions); + break; + } else { + ogs_error("Internal Server Error."); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR, 0, &message, "Internal Server Error.", message.h.method, NULL, maf_management_api, app_meta)); + } + DEFAULT + ogs_error("Invalid HTTP method [%s]", message.h.method); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 0, &message, "Invalid HTTP method.", message.h.method, NULL, maf_management_api, app_meta)); + + END + break; + + DEFAULT + char *err; + ogs_error("Invalid resource name [%s]", message.h.resource.component[0]); + asprintf(&err,"Invalid resource name [%s]", message.h.resource.component[0]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid resource name", err, NULL, NULL, app_meta)); + + END + ogs_sbi_message_free(&message); + break; + + DEFAULT + ogs_error("Invalid API name [%s]", message.h.service.name); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid API name.", message.h.service.name, NULL, NULL, app_meta)); + + END + break; + + case OGS_EVENT_SBI_CLIENT: + ogs_assert(e); + + response = e->h.sbi.response; + ogs_assert(response); + rv = ogs_sbi_parse_header(&message, &response->h); + if (rv != OGS_OK) { + ogs_error("ogs_sbi_parse_header() failed"); + ogs_sbi_message_free(&message); + ogs_sbi_response_free(response); + break; + } + { + ogs_hash_index_t *hi; + for (hi = ogs_hash_first(response->http.headers); + hi; hi = ogs_hash_next(hi)) { + if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { + message.http.content_type = ogs_hash_this_val(hi); + } else if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_LOCATION)) { + message.http.location = ogs_hash_this_val(hi); + } + } + } + + message.res_status = response->status; + + SWITCH(message.h.service.name) + CASE("3gpp-m3") + SWITCH(message.h.resource.component[0]) + CASE("content-hosting-configurations") + + msaf_application_server_state_node_t *as_state; + as_state = e->application_server_state; + ogs_assert(as_state); + + if (message.h.resource.component[1] && message.h.resource.component[2]) { + + if (!strcmp(message.h.resource.component[2],"purge")) { + + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) + purge_resource_id_node_t *purge_node = e->purge_node; + + if (response->status == 204 || response->status == 200) { + + purge_resource_id_node_t *content_hosting_cache, *next = NULL; + + if (response->status == 200) { + //parse the int in response body + //Add the integer to purge_node->m1_purge_info->purged_entries_total; + { + ogs_hash_index_t *hi; + for (hi = ogs_hash_first(request->http.headers); + hi; hi = ogs_hash_next(hi)) { + if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { + if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/json")) { + char *err = NULL; + char *type = NULL; + type = (char *)ogs_hash_this_val(hi); + ogs_error("Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); + asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); + + ogs_assert(true == nf_server_send_error(stream, 415, 2, &message, "Provisioning session does not exist.", err, NULL, m3_contenthostingprovisioning_api, app_meta)); + ogs_sbi_message_free(&message); + return; + } + } + } + } + + int purged_items_from_as = 0; + cJSON *entry; + cJSON *number_of_cache_entries = cJSON_Parse(response->http.content); + cJSON_ArrayForEach(entry, number_of_cache_entries) { + ogs_debug("Purged entries return %d\n", entry->valueint); + purged_items_from_as = entry->valueint; + + } + purge_node->m1_purge_info->purged_entries_total += purged_items_from_as; + + } + + + ogs_list_for_each_safe(&as_state->purge_content_hosting_cache, next, content_hosting_cache){ + if (purge_node->purge_regex) { + if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id) && !strcmp(content_hosting_cache->purge_regex, purge_node->purge_regex)) + break; + } else if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id)) { + break; + } + } + if(content_hosting_cache){ + ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); + ogs_debug("M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); + + purge_node->m1_purge_info->refs--; + ogs_debug(" After decrement, M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); + if(!purge_node->m1_purge_info->refs){ + // send M1 response with total from purge_node->m1_purge_info->purged_entries_total + // ogs_free(purge_node->m1_purge_info); + ogs_sbi_response_t *response; + cJSON *purged_entries_total_json = cJSON_CreateNumber(purge_node->m1_purge_info->purged_entries_total); + char *purged_entries_total = cJSON_Print(purged_entries_total_json); + response = ogs_sbi_response_new(); + response->http.content_length = strlen(purged_entries_total); + response->http.content = purged_entries_total; + response->status = 200; + ogs_sbi_header_set(response->http.headers, "Content-Type", "application/json"); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(purge_node->m1_purge_info->m1_stream, response)); + + if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); + if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); + if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); + ogs_free(content_hosting_cache); + } + msaf_application_server_state_log(&as_state->purge_content_hosting_cache, "Purge Content Hosting Cache list"); + + } + } + + + if((response->status == 404) || (response->status == 413) || (response->status == 414) || (response->status == 415) || (response->status == 422) || (response->status == 500) || (response->status == 503)) { + char *error; + purge_resource_id_node_t *content_hosting_cache, *next = NULL; + cJSON *purge_cache_err = NULL; + if(response->http.content){ + purge_cache_err = cJSON_Parse(response->http.content); + char *txt = cJSON_Print(purge_cache_err); + ogs_debug("txt:%s", txt); + } + + if(response->status == 404) { + + ogs_error("Error message from the Application Server [%s] with response code [%d]: Cache not found\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 413) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Pay load too large\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 414) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: URI too long\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 415) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Unsupported media type\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 422) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Unprocessable Entity\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 500) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Internal server error\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 503) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Service Unavailable\n", as_state->application_server->canonicalHostname, response->status); + } else { + + ogs_error("Application Server [%s] sent unrecognised response code [%d]", as_state->application_server->canonicalHostname, response->status); + } + + if (purge_node->purge_regex) { + error = ogs_msprintf("Application Server possibly encountered problem with regex %s", purge_node->purge_regex); + } else { + error = ogs_msprintf("Application Server unable to process the contained instructions"); + } + + + ogs_assert(true == nf_server_send_error( purge_node->m1_purge_info->m1_stream, + response->status, 3, &purge_node->m1_purge_info->m1_message, "Problem occured during cache purge", error, purge_cache_err, m1_contenthostingprovisioning_api, app_meta)); + + ogs_list_for_each_safe(&as_state->purge_content_hosting_cache, next, content_hosting_cache){ + if (purge_node->purge_regex) { + if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id) && !strcmp(content_hosting_cache->purge_regex, purge_node->purge_regex)) { + + ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); + ogs_debug("M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); + if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); + if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); + if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); + ogs_free(content_hosting_cache); + + } + } else if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id)) { + + ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); + ogs_debug("M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); + if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); + if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); + if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); + ogs_free(content_hosting_cache); + + } + } + ogs_free(error); + cJSON_Delete(purge_cache_err); + + } + + next_action_for_application_server(as_state); + break; + END + break; + + } + } else if (message.h.resource.component[1]) { + + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) + + if (response->status == 201) { + + ogs_debug("[%s] Method [%s] with Response [%d] recieved for Content Hosting Configuration [%s]", message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); + + resource_id_node_t *content_hosting_configuration; + ogs_list_for_each(&as_state->upload_content_hosting_configurations,content_hosting_configuration) { + if(!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) + break; + } + if(content_hosting_configuration) { + + ogs_debug("Removing %s from upload_content_hosting_configurations", content_hosting_configuration->state); + ogs_list_remove(&as_state->upload_content_hosting_configurations, content_hosting_configuration); + ogs_debug("Adding %s to current_content_hosting_configurations",content_hosting_configuration->state); + ogs_list_add(as_state->current_content_hosting_configurations, content_hosting_configuration); + } + + } + if(response->status == 405){ + ogs_error("Content Hosting Configuration resource already exist at the specified path\n"); + } + if(response->status == 413){ + ogs_error("Payload too large\n"); + } + if(response->status == 414){ + ogs_error("URI too long\n"); + } + if(response->status == 415){ + ogs_error("Unsupported media type\n"); + } + if(response->status == 500){ + ogs_error("Internal server error\n"); + } + if(response->status == 503){ + ogs_error("Service unavailable\n"); + } + next_action_for_application_server(as_state); + break; + CASE(OGS_SBI_HTTP_METHOD_PUT) + if(response->status == 200 || response->status == 204) { + + ogs_debug("[%s] Method [%s] with Response [%d] recieved for Content Hosting Configuration [%s]", message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); + resource_id_node_t *content_hosting_configuration; + ogs_list_for_each(&as_state->upload_content_hosting_configurations,content_hosting_configuration){ + if(!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) + break; + } + if(content_hosting_configuration) { + + ogs_debug("Removing %s from upload_content_hosting_configurations", content_hosting_configuration->state); + ogs_free(content_hosting_configuration->state); + ogs_list_remove(&as_state->upload_content_hosting_configurations, content_hosting_configuration); + ogs_free(content_hosting_configuration); + } + + } + if(response->status == 404){ + ogs_error("Not Found\n"); + } + if(response->status == 413){ + ogs_error("Payload too large\n"); + } + if(response->status == 414){ + ogs_error("URI too long\n"); + } + if(response->status == 415){ + ogs_error("Unsupported Media Type\n"); + } + if(response->status == 500){ + ogs_error("Internal Server Error\n"); + } + if(response->status == 503){ + ogs_error("Service Unavailable\n"); + } + next_action_for_application_server(as_state); + break; + CASE(OGS_SBI_HTTP_METHOD_DELETE) + if(response->status == 204) { + + ogs_debug("[%s] Method [%s] with Response [%d] recieved for Content Hosting Configuration [%s]", message.h.resource.component[0], message.h.method, response->status,message.h.resource.component[1]); + + resource_id_node_t *content_hosting_configuration, *next = NULL; + resource_id_node_t *delete_content_hosting_configuration, *node = NULL; + + if(as_state->current_content_hosting_configurations) { + + ogs_list_for_each_safe(as_state->current_content_hosting_configurations, next, content_hosting_configuration){ + + if(!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) + break; + } + } + + if(content_hosting_configuration) { + + msaf_application_server_state_log(as_state->current_content_hosting_configurations, "Current Content Hosting Configurations"); + + ogs_debug("Removing %s from current_content_hosting_configurations", content_hosting_configuration->state); + ogs_free(content_hosting_configuration->state); + ogs_list_remove(as_state->current_content_hosting_configurations, content_hosting_configuration); + ogs_free(content_hosting_configuration); + msaf_application_server_state_log(as_state->current_content_hosting_configurations, "Current Content Hosting Configurations"); + } + + ogs_list_for_each_safe(&as_state->delete_content_hosting_configurations, node, delete_content_hosting_configuration) { + + if (!strcmp(delete_content_hosting_configuration->state, message.h.resource.component[1])) { + + msaf_application_server_state_log(&as_state->delete_content_hosting_configurations, "Delete Content Hosting Configurations"); + + ogs_debug("Destroying Content Hosting Configuration: %s", delete_content_hosting_configuration->state); + ogs_free(delete_content_hosting_configuration->state); + ogs_list_remove(&as_state->delete_content_hosting_configurations, delete_content_hosting_configuration); + ogs_free(delete_content_hosting_configuration); + + msaf_application_server_state_log(&as_state->delete_content_hosting_configurations, "Delete Content Hosting Configurations"); + } + } + + } + if(response->status == 404){ + ogs_error("Not Found\n"); + } + if(response->status == 413){ + ogs_error("Payload too large\n"); + } + if(response->status == 414){ + ogs_error("URI too long\n"); + } + if(response->status == 415){ + ogs_error("Unsupported Media Type\n"); + } + if(response->status == 500){ + ogs_error("Internal Server Error\n"); + } + if(response->status == 503){ + ogs_error("Service Unavailable\n"); + } + next_action_for_application_server(as_state); + break; + DEFAULT + ogs_error("Unknown M3 Content Hosting Configuration operation [%s]", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Content Hosting Configuration operation", message.h.resource.component[1], NULL, NULL, app_meta)); + break; + END + break; + } else { + cJSON *entry; + cJSON *chc_array = cJSON_Parse(response->http.content); + resource_id_node_t *current_chc; + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_GET) + + if(response->status == 200) { + + ogs_debug("[%s] Method [%s] with Response [%d] for Content Hosting Configuration operation [%s]", + message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); + + if (as_state->current_content_hosting_configurations == NULL) { + as_state->current_content_hosting_configurations = ogs_calloc(1,sizeof(*as_state->current_content_hosting_configurations)); + ogs_assert(as_state->current_content_hosting_configurations); + ogs_list_init(as_state->current_content_hosting_configurations); + + } else { + resource_id_node_t *next, *node; + ogs_list_for_each_safe(as_state->current_content_hosting_configurations, next, node) { + ogs_free(node->state); + ogs_list_remove(as_state->current_content_hosting_configurations, node); + ogs_free(node); + } + } + cJSON_ArrayForEach(entry, chc_array) { + char *id = strrchr(entry->valuestring, '/'); + if (id == NULL) { + id = entry->valuestring; + } else { + id++; + } + current_chc = ogs_calloc(1, sizeof(*current_chc)); + current_chc->state = ogs_strdup(id); + ogs_debug("Adding [%s] to the current Content Hosting Configuration list",current_chc->state); + ogs_list_add(as_state->current_content_hosting_configurations, current_chc); + } + + cJSON_Delete(chc_array); + } + if (response->status == 500){ + ogs_error("Received Internal Server error\n"); + } + if (response->status == 503) { + ogs_error("Service Unavailable\n"); + } + next_action_for_application_server(as_state); + break; + DEFAULT + char *err; + ogs_error("Unknown M3 Content Hosting Configuration operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + asprintf(&err, "Unknown M3 Content Hosting Configuration operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Content Hosting Configuration operation", err, NULL, NULL, app_meta)); + + break; + END + break; + } + next_action_for_application_server(as_state); + + break; + + CASE("certificates") + + msaf_application_server_state_node_t *as_state; + as_state = e->application_server_state; + ogs_assert(as_state); + if (message.h.resource.component[1]) { + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) + if(response->status == 201) { + + ogs_debug("[%s] Method [%s] with Response [%d] recieved for certificate [%s]", message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); + + resource_id_node_t *certificate; + + //Iterate upload_certs and find match strcmp resource component 0 + ogs_list_for_each(&as_state->upload_certificates,certificate){ + if(!strcmp(certificate->state, message.h.resource.component[1])) + break; + } + if(certificate) { + + ogs_debug("Removing certificate [%s] from upload_certificates", certificate->state); + + ogs_list_remove(&as_state->upload_certificates, certificate); + + ogs_debug("Adding certificate [%s] to current_certificates", certificate->state); + + ogs_list_add(as_state->current_certificates, certificate); + // ogs_free(upload_cert_id); + } + } + if(response->status == 405){ + ogs_error("Server Certificate resource already exist at the specified path\n"); + } + if(response->status == 413){ + ogs_error("Payload too large\n"); + } + if(response->status == 414){ + ogs_error("URI too long\n"); + } + if(response->status == 415){ + ogs_error("Unsupported media type\n"); + } + if(response->status == 500){ + ogs_error("Internal server error\n"); + } + if(response->status == 503){ + ogs_error("Service unavailable\n"); + } + next_action_for_application_server(as_state); + break; + CASE(OGS_SBI_HTTP_METHOD_PUT) + if(response->status == 200 || response->status == 204) { + + ogs_debug("[%s] Method [%s] with Response [%d] recieved for certificate [%s]", message.h.resource.component[0], message.h.method, response->status,message.h.resource.component[1]); + + resource_id_node_t *certificate; + + msaf_application_server_state_log(&as_state->upload_certificates, "Upload Certificates"); + + //Iterate upload_certs and find match strcmp resource component 0 + ogs_list_for_each(&as_state->upload_certificates,certificate){ + + if(!strcmp(certificate->state, message.h.resource.component[1])) + break; + } + + if(!certificate){ + ogs_debug("Certificate %s not found in upload certificates", message.h.resource.component[1]); + } else { + ogs_debug("Removing certificate [%s] from upload_certificates", certificate->state); + ogs_free(certificate->state); + + ogs_list_remove(&as_state->upload_certificates, certificate); + ogs_free(certificate); + } + } + if(response->status == 404){ + ogs_error("Not Found\n"); + } + if(response->status == 413){ + ogs_error("Payload too large\n"); + } + if(response->status == 414){ + ogs_error("URI too long\n"); + } + if(response->status == 415){ + ogs_error("Unsupported Media Type\n"); + } + if(response->status == 500){ + ogs_error("Internal Server Error\n"); + } + if(response->status == 503){ + ogs_error("Service Unavailable\n"); + } + next_action_for_application_server(as_state); + break; + CASE(OGS_SBI_HTTP_METHOD_DELETE) + if(response->status == 204) { + + ogs_debug("[%s] Method [%s] with Response [%d] recieved for Certificate [%s]", message.h.resource.component[0], message.h.method, response->status,message.h.resource.component[1]); + + resource_id_node_t *certificate, *next = NULL; + resource_id_node_t *delete_certificate, *node = NULL; + + if(as_state->current_certificates) { + ogs_list_for_each_safe(as_state->current_certificates, next, certificate){ + + if(!strcmp(certificate->state, message.h.resource.component[1])) + break; + } + } + + if(certificate) { + + msaf_application_server_state_log(as_state->current_certificates, "Current Certificates"); + + ogs_debug("Removing certificate [%s] from current_certificates", certificate->state); + ogs_free(certificate->state); + + ogs_list_remove(as_state->current_certificates, certificate); + ogs_free(certificate); + msaf_application_server_state_log(as_state->current_certificates, "Current Certificates"); + } + + + ogs_list_for_each_safe(&as_state->delete_certificates, node, delete_certificate){ + + if(!strcmp(delete_certificate->state, message.h.resource.component[1])) { + msaf_application_server_state_log(&as_state->delete_certificates, "Delete Certificates"); + + ogs_debug("Destroying Certificate: %s", delete_certificate->state); + ogs_free(delete_certificate->state); + ogs_list_remove(&as_state->delete_certificates, delete_certificate); + ogs_free(delete_certificate); + msaf_application_server_state_log(&as_state->delete_certificates, "Delete Certificates"); + + } + } + } + if(response->status == 404){ + ogs_error("Not Found\n"); + } + if(response->status == 413){ + ogs_error("Payload too large\n"); + } + if(response->status == 414){ + ogs_error("URI too long\n"); + } + if(response->status == 415){ + ogs_error("Unsupported Media Type\n"); + } + if(response->status == 500){ + ogs_error("Internal Server Error\n"); + } + if(response->status == 503){ + ogs_error("Service Unavailable\n"); + } + next_action_for_application_server(as_state); + break; + DEFAULT + ogs_error("Unknown M3 certificate operation [%s]", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 certificate operation.", message.h.resource.component[1], NULL, NULL, app_meta)); + break; + END + break; + } else { + cJSON *entry; + cJSON *cert_array = cJSON_Parse(response->http.content); + resource_id_node_t *current_cert; + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_GET) + + if(response->status == 200) { + + ogs_debug("[%s] Method [%s] with Response [%d] received", + message.h.resource.component[0], message.h.method, response->status); + + if (as_state->current_certificates == NULL) { + as_state->current_certificates = ogs_calloc(1,sizeof(*as_state->current_certificates)); + ogs_assert(as_state->current_certificates); + ogs_list_init(as_state->current_certificates); + + } else { + resource_id_node_t *next, *node; + ogs_list_for_each_safe(as_state->current_certificates, next, node) { + + ogs_debug("Removing certificate [%s] from current_certificates", node->state); + + ogs_free(node->state); + ogs_list_remove(as_state->current_certificates, node); + ogs_free(node); + } + } + cJSON_ArrayForEach(entry, cert_array) { + char *id = strrchr(entry->valuestring, '/'); + if (id == NULL) { + id = entry->valuestring; + } else { + id++; + } + current_cert = ogs_calloc(1, sizeof(*current_cert)); + current_cert->state = ogs_strdup(id); + ogs_debug("Adding certificate [%s] to Current certificates", current_cert->state); + ogs_list_add(as_state->current_certificates, current_cert); + } + + cJSON_Delete(cert_array); + } + if (response->status == 500){ + ogs_error("Received Internal Server error"); + } + if (response->status == 503) { + ogs_error("Service Unavailable"); + } + next_action_for_application_server(as_state); + break; + DEFAULT + char *err; + ogs_error("Unknown M3 certificate operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + asprintf(&err, "Unsupported M3 Certificate operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Certificate operation", err, NULL, NULL, app_meta)); + + break; + END + break; + } + next_action_for_application_server(as_state); + + break; + + DEFAULT + ogs_error("Unknown M3 operation [%s]", message.h.resource.component[0]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unsupported M3 operation", message.h.resource.component[0], NULL, NULL, app_meta)); + break; + END + break; + + CASE(OGS_SBI_SERVICE_NAME_NNRF_NFM) + + SWITCH(message.h.resource.component[0]) + CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES) + nf_instance = e->h.sbi.data; + ogs_assert(nf_instance); + ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); + + e->h.sbi.message = &message; + ogs_fsm_dispatch(&nf_instance->sm, e); + break; + + CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS) + subscription_data = e->h.sbi.data; + ogs_assert(subscription_data); + + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) + if (message.res_status == OGS_SBI_HTTP_STATUS_CREATED || + message.res_status == OGS_SBI_HTTP_STATUS_OK) { + ogs_nnrf_nfm_handle_nf_status_subscribe( + subscription_data, &message); + } else { + ogs_error("HTTP response error : %d", + message.res_status); + } + break; + + CASE(OGS_SBI_HTTP_METHOD_DELETE) + if (message.res_status == OGS_SBI_HTTP_STATUS_NO_CONTENT) { + ogs_sbi_subscription_data_remove(subscription_data); + } else { + ogs_error("HTTP response error : %d", + message.res_status); + } + break; + + DEFAULT + ogs_error("Invalid HTTP method [%s]", message.h.method); + ogs_assert_if_reached(); + END + break; + + DEFAULT + ogs_error("Invalid resource name [%s]", + message.h.resource.component[0]); + ogs_assert_if_reached(); + END + break; + + DEFAULT + ogs_error("Invalid service name [%s]", message.h.service.name); + ogs_assert_if_reached(); + END + + ogs_sbi_message_free(&message); + ogs_sbi_response_free(response); + break; + + case OGS_EVENT_SBI_TIMER: + ogs_assert(e); + + switch(e->h.timer_id) { + case OGS_TIMER_NF_INSTANCE_REGISTRATION_INTERVAL: + case OGS_TIMER_NF_INSTANCE_HEARTBEAT_INTERVAL: + case OGS_TIMER_NF_INSTANCE_NO_HEARTBEAT: + case OGS_TIMER_NF_INSTANCE_VALIDITY: + nf_instance = e->h.sbi.data; + ogs_assert(nf_instance); + ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); + + ogs_fsm_dispatch(&nf_instance->sm, e); + if (OGS_FSM_CHECK(&nf_instance->sm, ogs_sbi_nf_state_exception)) + ogs_error("State machine exception [%d]", e->h.timer_id); + break; + + case OGS_TIMER_SUBSCRIPTION_VALIDITY: + subscription_data = e->h.sbi.data; + ogs_assert(subscription_data); + + ogs_assert(true == + ogs_nnrf_nfm_send_nf_status_subscribe(subscription_data)); + + ogs_debug("Subscription validity expired [%s]", + subscription_data->id); + ogs_sbi_subscription_data_remove(subscription_data); + break; + + case OGS_TIMER_SBI_CLIENT_WAIT: + sbi_xact = e->h.sbi.data; + ogs_assert(sbi_xact); + + stream = sbi_xact->assoc_stream; + + ogs_sbi_xact_remove(sbi_xact); + + ogs_error("Cannot receive SBI message"); + if (stream) { + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_GATEWAY_TIMEOUT, NULL, + "Cannot receive SBI message", NULL)); + } + break; + + default: + ogs_error("Unknown timer[%s:%d]", + ogs_timer_get_name(e->h.timer_id), e->h.timer_id); + } + break; + + default: + ogs_error("No handler for event %s", msaf_event_get_name(e)); + break; + } + ogs_free(nf_name); +} + +/* vim:ts=8:sts=4:sw=4:expandtab: +*/ diff --git a/src/5gmsaf/msaf-m5-sm.c b/src/5gmsaf/msaf-m5-sm.c new file mode 100644 index 0000000..bedfdc1 --- /dev/null +++ b/src/5gmsaf/msaf-m5-sm.c @@ -0,0 +1,308 @@ +/* + * License: 5G-MAG Public License (v1.0) + * Author: Dev Audsin + * Copyright: (C) 2022 British Broadcasting Corporation + * + * For full license terms please see the LICENSE file distributed with this + * program. If this file is missing then the license can be retrieved from + * https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view + */ + + +#include "ogs-sbi.h" +#include "sbi-path.h" +#include "context.h" +#include "certmgr.h" +#include "server.h" +#include "response-cache-control.h" +#include "msaf-version.h" +#include "msaf-sm.h" +#include "openapi/api/TS26512_M5_ServiceAccessInformationAPI-info.h" + +const nf_server_interface_metadata_t +m5_serviceaccessinformation_api_metadata = { + M5_SERVICEACCESSINFORMATION_API_NAME, + M5_SERVICEACCESSINFORMATION_API_VERSION +}; + +void msaf_m5_state_initial(ogs_fsm_t *s, msaf_event_t *e) +{ + msaf_sm_debug(e); + + ogs_assert(s); + + OGS_FSM_TRAN(s, &msaf_m5_state_functional); +} + +void msaf_m5_state_final(ogs_fsm_t *s, msaf_event_t *e) +{ + msaf_sm_debug(e); + + ogs_assert(s); +} + +void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e) +{ + int rv; + + ogs_sbi_stream_t *stream = NULL; + ogs_sbi_request_t *request = NULL; + + ogs_sbi_nf_instance_t *nf_instance = NULL; + ogs_sbi_subscription_data_t *subscription_data = NULL; + ogs_sbi_response_t *response = NULL; + ogs_sbi_message_t message; + ogs_sbi_xact_t *sbi_xact = NULL; + + msaf_sm_debug(e); + + char *nf_name = ogs_msprintf("5GMSdAF-%s", msaf_self()->server_name); + const nf_server_app_metadata_t app_metadata = { MSAF_NAME, MSAF_VERSION, nf_name}; + const nf_server_interface_metadata_t *m5_serviceaccessinformation_api = &m5_serviceaccessinformation_api_metadata; + const nf_server_app_metadata_t *app_meta = &app_metadata; + + ogs_assert(s); + + switch (e->h.id) { + case OGS_FSM_ENTRY_SIG: + ogs_info("[%s] MSAF M5 Running", ogs_sbi_self()->nf_instance->id); + + break; + + case OGS_FSM_EXIT_SIG: + break; + + case OGS_EVENT_SBI_SERVER: + request = e->h.sbi.request; + ogs_assert(request); + stream = e->h.sbi.data; + ogs_assert(stream); + message = *(e->message); + + SWITCH(message.h.service.name) + CASE("3gpp-m5") + if (strcmp(message.h.api.version, "v2") != 0) { + char *error; + ogs_error("Not supported version [%s]", message.h.api.version); + + error = ogs_msprintf("Version [%s] not supported", message.h.api.version); + + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL, app_meta)); + + ogs_sbi_message_free(&message); + ogs_free(error); + + break; + } + SWITCH(message.h.resource.component[0]) + CASE("service-access-information") + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_GET) + cJSON *service_access_information; + msaf_provisioning_session_t *msaf_provisioning_session = NULL; + msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + + if(msaf_provisioning_session == NULL) { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] not found.", message.h.resource.component[1]); + ogs_error("Client requested invalid Provisioning Session [%s]", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Provisioning Session not found.", err, NULL, m5_serviceaccessinformation_api, app_meta)); + + } else if (msaf_provisioning_session->serviceAccessInformation) { + service_access_information = msaf_context_retrieve_service_access_information(message.h.resource.component[1]); + if (service_access_information != NULL) { + ogs_sbi_response_t *response; + char *text; + text = cJSON_Print(service_access_information); + response = nf_server_new_response(NULL, "application/json", msaf_provisioning_session->serviceAccessInformationCreated, msaf_provisioning_session->serviceAccessInformationHash, msaf_self()->config.server_response_cache_control->m5_service_access_information_response_max_age, NULL, m5_serviceaccessinformation_api, app_meta); + nf_server_populate_response(response, strlen(text), text, 201); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + cJSON_Delete(service_access_information); + } else { + char *err = NULL; + asprintf(&err,"Service Access Information for the Provisioning Session [%s] not found.", message.h.resource.component[1]); + ogs_error("Client requested invalid Service Access Information for the Provisioning Session [%s]", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL, m5_serviceaccessinformation_api, app_meta)); + + + } + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] has no Service Access Information associated with it.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] has no Service Access Information associated with it", message.h.resource.component[1]); + + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL, m5_serviceaccessinformation_api, app_meta)); + + } + break; + DEFAULT + ogs_error("Invalid HTTP method [%s]", message.h.method); + + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 1, &message, "Invalid HTTP method.", message.h.method, NULL, NULL, app_meta)); + + END + break; + DEFAULT + ogs_error("Invalid resource name [%s]", + message.h.resource.component[0]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid resource name.", message.h.resource.component[0], NULL, NULL, app_meta)); + + END + ogs_sbi_message_free(&message); + break; + DEFAULT + ogs_error("Invalid API name [%s]", message.h.service.name); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid API name.", message.h.service.name, NULL, NULL, app_meta)); + + END + break; + + case OGS_EVENT_SBI_CLIENT: + ogs_assert(e); + + response = e->h.sbi.response; + ogs_assert(response); + rv = ogs_sbi_parse_header(&message, &response->h); + if (rv != OGS_OK) { + ogs_error("ogs_sbi_parse_header() failed"); + ogs_sbi_message_free(&message); + ogs_sbi_response_free(response); + break; + } + { + ogs_hash_index_t *hi; + for (hi = ogs_hash_first(response->http.headers); + hi; hi = ogs_hash_next(hi)) { + if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { + message.http.content_type = ogs_hash_this_val(hi); + } else if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_LOCATION)) { + message.http.location = ogs_hash_this_val(hi); + } + } + } + + message.res_status = response->status; + + SWITCH(message.h.service.name) + CASE(OGS_SBI_SERVICE_NAME_NNRF_NFM) + + SWITCH(message.h.resource.component[0]) + CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES) + nf_instance = e->h.sbi.data; + ogs_assert(nf_instance); + ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); + + e->h.sbi.message = &message; + ogs_fsm_dispatch(&nf_instance->sm, e); + break; + + CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS) + subscription_data = e->h.sbi.data; + ogs_assert(subscription_data); + + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) + if (message.res_status == OGS_SBI_HTTP_STATUS_CREATED || + message.res_status == OGS_SBI_HTTP_STATUS_OK) { + ogs_nnrf_nfm_handle_nf_status_subscribe( + subscription_data, &message); + } else { + ogs_error("HTTP response error : %d", + message.res_status); + } + break; + + CASE(OGS_SBI_HTTP_METHOD_DELETE) + if (message.res_status == OGS_SBI_HTTP_STATUS_NO_CONTENT) { + ogs_sbi_subscription_data_remove(subscription_data); + } else { + ogs_error("HTTP response error : %d", + message.res_status); + } + break; + + DEFAULT + ogs_error("Invalid HTTP method [%s]", message.h.method); + ogs_assert_if_reached(); + END + break; + + DEFAULT + ogs_error("Invalid resource name [%s]", + message.h.resource.component[0]); + ogs_assert_if_reached(); + END + break; + + DEFAULT + ogs_error("Invalid service name [%s]", message.h.service.name); + ogs_assert_if_reached(); + END + + ogs_sbi_message_free(&message); + ogs_sbi_response_free(response); + break; + + case OGS_EVENT_SBI_TIMER: + ogs_assert(e); + + switch(e->h.timer_id) { + case OGS_TIMER_NF_INSTANCE_REGISTRATION_INTERVAL: + case OGS_TIMER_NF_INSTANCE_HEARTBEAT_INTERVAL: + case OGS_TIMER_NF_INSTANCE_NO_HEARTBEAT: + case OGS_TIMER_NF_INSTANCE_VALIDITY: + nf_instance = e->h.sbi.data; + ogs_assert(nf_instance); + ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); + + ogs_fsm_dispatch(&nf_instance->sm, e); + if (OGS_FSM_CHECK(&nf_instance->sm, ogs_sbi_nf_state_exception)) + ogs_error("State machine exception [%d]", e->h.timer_id); + break; + + case OGS_TIMER_SUBSCRIPTION_VALIDITY: + subscription_data = e->h.sbi.data; + ogs_assert(subscription_data); + + ogs_assert(true == + ogs_nnrf_nfm_send_nf_status_subscribe(subscription_data)); + + ogs_debug("Subscription validity expired [%s]", + subscription_data->id); + ogs_sbi_subscription_data_remove(subscription_data); + break; + + case OGS_TIMER_SBI_CLIENT_WAIT: + sbi_xact = e->h.sbi.data; + ogs_assert(sbi_xact); + + stream = sbi_xact->assoc_stream; + + ogs_sbi_xact_remove(sbi_xact); + + ogs_error("Cannot receive SBI message"); + if (stream) { + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_GATEWAY_TIMEOUT, NULL, + "Cannot receive SBI message", NULL)); + } + break; + + default: + ogs_error("Unknown timer[%s:%d]", + ogs_timer_get_name(e->h.timer_id), e->h.timer_id); + } + break; + + default: + ogs_error("No handler for event %s", msaf_event_get_name(e)); + break; + } + ogs_free(nf_name); +} + +/* vim:ts=8:sts=4:sw=4:expandtab: +*/ diff --git a/src/5gmsaf/msaf-mgmt-sm.c b/src/5gmsaf/msaf-mgmt-sm.c index 9bb553d..335e2b5 100644 --- a/src/5gmsaf/msaf-mgmt-sm.c +++ b/src/5gmsaf/msaf-mgmt-sm.c @@ -14,32 +14,32 @@ #include "server.h" #include "response-cache-control.h" #include "msaf-version.h" -#include "msaf-mgmt-sm.h" -#include "openapi/api/TS26512_M1_ProvisioningSessionsAPI-info.h" - +#include "msaf-sm.h" +#include "openapi/api/Maf_ManagementAPI-info.h" + const nf_server_interface_metadata_t -m1_mgmt_provisioningsession_api_metadata = { - M1_PROVISIONINGSESSIONS_API_NAME, - M1_PROVISIONINGSESSIONS_API_VERSION +maf_mgmt_api_metadata = { + MAF_MANAGEMENT_API_NAME, + MAF_MANAGEMENT_API_VERSION }; -void msaf_mgmt_state_initial(ogs_fsm_t *s, msaf_event_t *e) +void msaf_maf_mgmt_state_initial(ogs_fsm_t *s, msaf_event_t *e) { msaf_sm_debug(e); ogs_assert(s); - OGS_FSM_TRAN(s, &msaf_mgmt_state_functional); + OGS_FSM_TRAN(s, &msaf_maf_mgmt_state_functional); } -void msaf_mgmt_state_final(ogs_fsm_t *s, msaf_event_t *e) +void msaf_maf_mgmt_state_final(ogs_fsm_t *s, msaf_event_t *e) { msaf_sm_debug(e); ogs_assert(s); } -void msaf_mgmt_state_functional(ogs_fsm_t *s, msaf_event_t *e) +void msaf_maf_mgmt_state_functional(ogs_fsm_t *s, msaf_event_t *e) { int rv; @@ -54,9 +54,10 @@ void msaf_mgmt_state_functional(ogs_fsm_t *s, msaf_event_t *e) msaf_sm_debug(e); - msaf_context_server_name_set(); + if (!msaf_self()->server_name) msaf_context_server_name_set(); char *nf_name = ogs_msprintf("5GMSdAF-%s", msaf_self()->server_name); const nf_server_app_metadata_t app_metadata = { MSAF_NAME, MSAF_VERSION, nf_name}; + const nf_server_interface_metadata_t *maf_management_api = &maf_mgmt_api_metadata; const nf_server_app_metadata_t *app_meta = &app_metadata; ogs_assert(s); @@ -74,110 +75,16 @@ void msaf_mgmt_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_assert(request); stream = e->h.sbi.data; ogs_assert(stream); - - rv = ogs_sbi_parse_header(&message, &request->h); - if (rv != OGS_OK) { - ogs_error("ogs_sbi_parse_header() failed"); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "cannot parse HTTP message", NULL, NULL, NULL, app_meta)); - - break; - } + message = *(e->message); SWITCH(message.h.service.name) - CASE(OGS_SBI_SERVICE_NAME_NNRF_NFM) - if (strcmp(message.h.api.version, OGS_SBI_API_V1) != 0) { - ogs_error("Not supported version [%s]", message.h.api.version); - ogs_assert(true == ogs_sbi_server_send_error( - stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, - &message, "Not supported version", NULL)); - ogs_sbi_message_free(&message); - break; - } - SWITCH(message.h.resource.component[0]) - CASE(OGS_SBI_RESOURCE_NAME_NF_STATUS_NOTIFY) - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_POST) - ogs_nnrf_nfm_handle_nf_status_notify(stream, &message); - break; - - DEFAULT - ogs_error("Invalid HTTP method [%s]", message.h.method); - ogs_assert(true == - ogs_sbi_server_send_error(stream, - OGS_SBI_HTTP_STATUS_FORBIDDEN, &message, - "Invalid HTTP method", message.h.method)); - END - break; - - DEFAULT - ogs_error("Invalid resource name [%s]", - message.h.resource.component[0]); - ogs_assert(true == - ogs_sbi_server_send_error(stream, - OGS_SBI_HTTP_STATUS_BAD_REQUEST, &message, - "Invalid resource name", - message.h.resource.component[0])); - END - ogs_sbi_message_free(&message); - break; - CASE("5gmag-rt-management") - if (strcmp(message.h.api.version, "v1") != 0) { - char *error; - ogs_error("Not supported version [%s]", message.h.api.version); - - error = ogs_msprintf("Version [%s] not supported", message.h.api.version); - - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL, app_meta)); - - ogs_sbi_message_free(&message); - ogs_free(error); - break; - } - - SWITCH(message.h.resource.component[0]) - - CASE("provisioning-sessions") - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_GET) - char *provisioning_sessions; - ogs_sbi_response_t *response; - provisioning_sessions = enumerate_provisioning_sessions(); - if (provisioning_sessions) { - response = nf_server_new_response(NULL, "application/json", 0, NULL, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, NULL, app_meta); - - nf_server_populate_response(response, strlen(provisioning_sessions), ogs_strdup(provisioning_sessions), 200); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - if (strcmp(provisioning_sessions,"[]")) ogs_free(provisioning_sessions); - break; - } else { - ogs_error("Internal Server Error."); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR, 0, &message, "Internal Server Error.", message.h.method, NULL, NULL, app_meta)); - - } - DEFAULT - ogs_error("Invalid HTTP method [%s]", message.h.method); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 1, &message, "Invalid HTTP method.", message.h.method, NULL, NULL, app_meta)); - END - break; - DEFAULT - char *err; - ogs_error("Invalid resource name [%s]", - message.h.resource.component[0]); - asprintf(&err,"Invalid resource name [%s]", message.h.resource.component[0]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid resource name", err, NULL, NULL, app_meta)); - - - END - ogs_sbi_message_free(&message); + ogs_fsm_dispatch(&msaf_self()->msaf_fsm.msaf_m1_sm, e); break; - - - + DEFAULT - ogs_error("Invalid API name [%s]", message.h.service.name); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid API name.", message.h.service.name, NULL, NULL, app_meta)); + ogs_error("Resource [%s] not found.", message.h.service.name); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_NOT_FOUND, 0, &message, "Not Found.", message.h.service.name, NULL, maf_management_api, app_meta)); END break; diff --git a/src/5gmsaf/msaf-mgmt-sm.h b/src/5gmsaf/msaf-mgmt-sm.h deleted file mode 100644 index 32fa42a..0000000 --- a/src/5gmsaf/msaf-mgmt-sm.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -License: 5G-MAG Public License (v1.0) -Copyright: (C) 2022 British Broadcasting Corporation - -For full license terms please see the LICENSE file distributed with this -program. If this file is missing then the license can be retrieved from -https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view - */ - -#ifndef MSAF_MGMT_SM_H -#define MSAF_MGMT_SM_H - -#include "event.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void msaf_mgmt_state_initial(ogs_fsm_t *s, msaf_event_t *e); -void msaf_mgmt_state_final(ogs_fsm_t *s, msaf_event_t *e); -void msaf_mgmt_state_functional(ogs_fsm_t *s, msaf_event_t *e); -void msaf_mgmt_state_exception(ogs_fsm_t *s, msaf_event_t *e); - -#define msaf_sm_debug(__pe) \ - ogs_debug("%s(): %s", __func__, msaf_event_get_name(__pe)) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/5gmsaf/msaf-sm.c b/src/5gmsaf/msaf-sm.c index 3f2fb0f..e21ca3d 100644 --- a/src/5gmsaf/msaf-sm.c +++ b/src/5gmsaf/msaf-sm.c @@ -16,50 +16,8 @@ #include "server.h" #include "response-cache-control.h" #include "msaf-version.h" -#include "ContentProtocolsDiscovery_body.h" -#include "openapi/api/TS26512_M1_ProvisioningSessionsAPI-info.h" -#include "openapi/api/TS26512_M1_ServerCertificatesProvisioningAPI-info.h" -#include "openapi/api/TS26512_M1_ContentHostingProvisioningAPI-info.h" -#include "openapi/api/M3_ServerCertificatesProvisioningAPI-info.h" -#include "openapi/api/M3_ContentHostingProvisioningAPI-info.h" -#include "openapi/api/TS26512_M5_ServiceAccessInformationAPI-info.h" -#include "openapi/api/TS26512_M1_ContentProtocolsDiscoveryAPI-info.h" - -const nf_server_interface_metadata_t -m1_provisioningsession_api_metadata = { - M1_PROVISIONINGSESSIONS_API_NAME, - M1_PROVISIONINGSESSIONS_API_VERSION -}; - -const nf_server_interface_metadata_t -m1_contenthostingprovisioning_api_metadata = { - M1_CONTENTHOSTINGPROVISIONING_API_NAME, - M1_CONTENTHOSTINGPROVISIONING_API_VERSION -}; - -const nf_server_interface_metadata_t -m1_contentprotocolsdiscovery_api_metadata = { - M1_CONTENTPROTOCOLSDISCOVERY_API_NAME, - M1_CONTENTPROTOCOLSDISCOVERY_API_VERSION -}; - -const nf_server_interface_metadata_t -m1_servercertificatesprovisioning_api_metadata = { - M1_SERVERCERTIFICATESPROVISIONING_API_NAME, - M1_SERVERCERTIFICATESPROVISIONING_API_VERSION -}; - -const nf_server_interface_metadata_t -m3_contenthostingprovisioning_api_metatdata = { - M3_CONTENTHOSTINGPROVISIONING_API_NAME, - M3_CONTENTHOSTINGPROVISIONING_API_VERSION -}; - -const nf_server_interface_metadata_t -m5_serviceaccessinformation_api_metadata = { - M5_SERVICEACCESSINFORMATION_API_NAME, - M5_SERVICEACCESSINFORMATION_API_VERSION -}; +#include "msaf-sm.h" + void msaf_state_initial(ogs_fsm_t *s, msaf_event_t *e) { @@ -73,6 +31,7 @@ void msaf_state_initial(ogs_fsm_t *s, msaf_event_t *e) void msaf_state_final(ogs_fsm_t *s, msaf_event_t *e) { msaf_sm_debug(e); + msaf_fsm_fini(); ogs_assert(s); } @@ -95,18 +54,13 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) msaf_context_server_name_set(); char *nf_name = ogs_msprintf("5GMSdAF-%s", msaf_self()->server_name); const nf_server_app_metadata_t app_metadata = { MSAF_NAME, MSAF_VERSION, nf_name}; - const nf_server_interface_metadata_t *m1_provisioningsession_api = &m1_provisioningsession_api_metadata; - const nf_server_interface_metadata_t *m1_contenthostingprovisioning_api = &m1_contenthostingprovisioning_api_metadata; - const nf_server_interface_metadata_t *m1_contentprotocolsdiscovery_api = &m1_contentprotocolsdiscovery_api_metadata; - const nf_server_interface_metadata_t *m1_servercertificatesprovisioning_api = &m1_servercertificatesprovisioning_api_metadata; - const nf_server_interface_metadata_t *m3_contenthostingprovisioning_api = &m3_contenthostingprovisioning_api_metatdata; - const nf_server_interface_metadata_t *m5_serviceaccessinformation_api = &m5_serviceaccessinformation_api_metadata; const nf_server_app_metadata_t *app_meta = &app_metadata; ogs_assert(s); switch (e->h.id) { case OGS_FSM_ENTRY_SIG: + msaf_fsm_init(); ogs_info("[%s] MSAF Running", ogs_sbi_self()->nf_instance->id); break; @@ -131,7 +85,6 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) break; } - rv = ogs_sbi_parse_header(&message, &request->h); if (rv != OGS_OK) { ogs_error("ogs_sbi_parse_header() failed"); @@ -179,18 +132,18 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) break; CASE("3gpp-m1") - if (strcmp(message.h.api.version, "v2") != 0) { - char *error; - ogs_error("Not supported version [%s]", message.h.api.version); - - error = ogs_msprintf("Version [%s] not supported", message.h.api.version); + if(check_event_addresses(e, msaf_self()->config.m1_server_sockaddr, msaf_self()->config.m1_server_sockaddr_v6)){ + e->message = &message; + ogs_fsm_dispatch(&msaf_self()->msaf_fsm.msaf_m1_sm, e); + - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL, app_meta)); - - ogs_sbi_message_free(&message); + } else { + char *error; + error = ogs_msprintf("Resource [%s] not found.", request->h.uri); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_NOT_FOUND, 1, NULL, "Not Found.", error, NULL, NULL, app_meta)); ogs_free(error); - break; } +<<<<<<< Updated upstream SWITCH(message.h.resource.component[0]) CASE("provisioning-sessions") @@ -1071,144 +1024,47 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid resource name", err, NULL, NULL, app_meta)); END +======= +>>>>>>> Stashed changes ogs_sbi_message_free(&message); break; CASE("5gmag-rt-management") - if (strcmp(message.h.api.version, "v1") != 0) { - char *error; - ogs_error("Not supported version [%s]", message.h.api.version); - - error = ogs_msprintf("Version [%s] not supported", message.h.api.version); + if(!msaf_self()->config.maf_mgmt_server_sockaddr && !msaf_self()->config.maf_mgmt_server_sockaddr_v6) { + if(check_event_addresses(e, msaf_self()->config.m1_server_sockaddr, msaf_self()->config.m1_server_sockaddr_v6)){ + e->message = &message; + ogs_fsm_dispatch(&msaf_self()->msaf_fsm.msaf_m1_sm, e); + } + } else + if(check_event_addresses(e, msaf_self()->config.maf_mgmt_server_sockaddr, msaf_self()->config.maf_mgmt_server_sockaddr_v6)){ + e->message = &message; + ogs_fsm_dispatch(&msaf_self()->msaf_fsm.msaf_maf_mgmt_sm, e); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL, app_meta)); - - ogs_sbi_message_free(&message); - ogs_free(error); - break; - } - if(msaf_self()->config.mgmt_server_sockaddr || msaf_self()->config.mgmt_server_sockaddr_v6) { - char *error; - ogs_error("Cannot access the resource through this network, use the management network instead."); - error = ogs_msprintf("Cannot access the resource through this network, use the management network instead."); - ogs_assert(true == nf_server_send_error(stream, 403, 1, NULL, "Forbidden resource", error, NULL, NULL, app_meta)); - ogs_sbi_message_free(&message); + } else { + char *error; + error = ogs_msprintf("Resource [%s] not found.", request->h.uri); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_NOT_FOUND, 1, NULL, "Not Found.", error, NULL, NULL, app_meta)); ogs_free(error); - break; - } - SWITCH(message.h.resource.component[0]) - - CASE("provisioning-sessions") - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_GET) - char *provisioning_sessions = NULL; - ogs_sbi_response_t *response; - provisioning_sessions = enumerate_provisioning_sessions(); - if(provisioning_sessions) { - response = nf_server_new_response(NULL, "application/json", 0, NULL, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, NULL, app_meta); - - nf_server_populate_response(response, strlen(provisioning_sessions), ogs_strdup(provisioning_sessions), 200); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - if (strcmp(provisioning_sessions,"[]")) ogs_free(provisioning_sessions); - break; - } else { - ogs_error("Internal Server Error."); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR, 0, &message, "Internal Server Error.", message.h.method, NULL, NULL, app_meta)); - } - DEFAULT - ogs_error("Invalid HTTP method [%s]", message.h.method); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 0, &message, "Invalid HTTP method.", message.h.method, NULL, NULL, app_meta)); - - END - break; - - DEFAULT - char *err; - ogs_error("Invalid resource name [%s]", message.h.resource.component[0]); - asprintf(&err,"Invalid resource name [%s]", message.h.resource.component[0]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid resource name", err, NULL, NULL, app_meta)); - - END ogs_sbi_message_free(&message); break; CASE("3gpp-m5") - if (strcmp(message.h.api.version, "v2") != 0) { - char *error; - ogs_error("Not supported version [%s]", message.h.api.version); - - error = ogs_msprintf("Version [%s] not supported", message.h.api.version); - - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL, app_meta)); + if(check_event_addresses(e, msaf_self()->config.m5_server_sockaddr, msaf_self()->config.m5_server_sockaddr_v6)){ + e->message = &message; + ogs_fsm_dispatch(&msaf_self()->msaf_fsm.msaf_m5_sm, e); - ogs_sbi_message_free(&message); + } else { + char *error; + error = ogs_msprintf("Resource [%s] not found.", request->h.uri); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_NOT_FOUND, 1, NULL, "Not Found.", error, NULL, NULL, app_meta)); ogs_free(error); - - break; } - SWITCH(message.h.resource.component[0]) - CASE("service-access-information") - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_GET) - cJSON *service_access_information; - msaf_provisioning_session_t *msaf_provisioning_session = NULL; - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - - if(msaf_provisioning_session == NULL) { - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] not found.", message.h.resource.component[1]); - ogs_error("Client requested invalid Provisioning Session [%s]", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Provisioning Session not found.", err, NULL, m5_serviceaccessinformation_api, app_meta)); - - } else if (msaf_provisioning_session->serviceAccessInformation) { - service_access_information = msaf_context_retrieve_service_access_information(message.h.resource.component[1]); - if (service_access_information != NULL) { - ogs_sbi_response_t *response; - char *text; - text = cJSON_Print(service_access_information); - response = nf_server_new_response(NULL, "application/json", msaf_provisioning_session->serviceAccessInformationCreated, msaf_provisioning_session->serviceAccessInformationHash, msaf_self()->config.server_response_cache_control->m5_service_access_information_response_max_age, NULL, m5_serviceaccessinformation_api, app_meta); - nf_server_populate_response(response, strlen(text), text, 201); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - cJSON_Delete(service_access_information); - } else { - char *err = NULL; - asprintf(&err,"Service Access Information for the Provisioning Session [%s] not found.", message.h.resource.component[1]); - ogs_error("Client requested invalid Service Access Information for the Provisioning Session [%s]", message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL, m5_serviceaccessinformation_api, app_meta)); - - - } - } else { - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] has no Service Access Information associated with it.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] has no Service Access Information associated with it", message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL, m5_serviceaccessinformation_api, app_meta)); - - } - break; - DEFAULT - ogs_error("Invalid HTTP method [%s]", message.h.method); - - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 1, &message, "Invalid HTTP method.", message.h.method, NULL, NULL, app_meta)); - - END - break; - DEFAULT - ogs_error("Invalid resource name [%s]", - message.h.resource.component[0]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid resource name.", message.h.resource.component[0], NULL, NULL, app_meta)); - - END ogs_sbi_message_free(&message); break; DEFAULT ogs_error("Invalid API name [%s]", message.h.service.name); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid API name.", message.h.service.name, NULL, NULL, app_meta)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid API name.", message.h.service.name, NULL, NULL, app_meta)); END break; @@ -1225,641 +1081,10 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_sbi_response_free(response); break; } - { - ogs_hash_index_t *hi; - for (hi = ogs_hash_first(response->http.headers); - hi; hi = ogs_hash_next(hi)) { - if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { - message.http.content_type = ogs_hash_this_val(hi); - } else if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_LOCATION)) { - message.http.location = ogs_hash_this_val(hi); - } - } - } - message.res_status = response->status; SWITCH(message.h.service.name) - CASE("3gpp-m3") - SWITCH(message.h.resource.component[0]) - CASE("content-hosting-configurations") - - msaf_application_server_state_node_t *as_state; - as_state = e->application_server_state; - ogs_assert(as_state); - - if (message.h.resource.component[1] && message.h.resource.component[2]) { - - if (!strcmp(message.h.resource.component[2],"purge")) { - - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_POST) - purge_resource_id_node_t *purge_node = e->purge_node; - - if (response->status == 204 || response->status == 200) { - - purge_resource_id_node_t *content_hosting_cache, *next = NULL; - - if (response->status == 200) { - //parse the int in response body - //Add the integer to purge_node->m1_purge_info->purged_entries_total; - { - ogs_hash_index_t *hi; - for (hi = ogs_hash_first(request->http.headers); - hi; hi = ogs_hash_next(hi)) { - if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { - if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/json")) { - char *err = NULL; - char *type = NULL; - type = (char *)ogs_hash_this_val(hi); - ogs_error("Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); - asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); - - ogs_assert(true == nf_server_send_error(stream, 415, 2, &message, "Provisioning session does not exist.", err, NULL, m3_contenthostingprovisioning_api, app_meta)); - ogs_sbi_message_free(&message); - return; - } - } - } - } - - int purged_items_from_as = 0; - cJSON *entry; - cJSON *number_of_cache_entries = cJSON_Parse(response->http.content); - cJSON_ArrayForEach(entry, number_of_cache_entries) { - ogs_debug("Purged entries return %d\n", entry->valueint); - purged_items_from_as = entry->valueint; - - } - purge_node->m1_purge_info->purged_entries_total += purged_items_from_as; - - } - - - ogs_list_for_each_safe(&as_state->purge_content_hosting_cache, next, content_hosting_cache){ - if (purge_node->purge_regex) { - if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id) && !strcmp(content_hosting_cache->purge_regex, purge_node->purge_regex)) - break; - } else if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id)) { - break; - } - } - if(content_hosting_cache){ - ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); - ogs_debug("M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); - - purge_node->m1_purge_info->refs--; - ogs_debug(" After decrement, M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); - if(!purge_node->m1_purge_info->refs){ - // send M1 response with total from purge_node->m1_purge_info->purged_entries_total - // ogs_free(purge_node->m1_purge_info); - ogs_sbi_response_t *response; - cJSON *purged_entries_total_json = cJSON_CreateNumber(purge_node->m1_purge_info->purged_entries_total); - char *purged_entries_total = cJSON_Print(purged_entries_total_json); - response = ogs_sbi_response_new(); - response->http.content_length = strlen(purged_entries_total); - response->http.content = purged_entries_total; - response->status = 200; - ogs_sbi_header_set(response->http.headers, "Content-Type", "application/json"); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(purge_node->m1_purge_info->m1_stream, response)); - - if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); - if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); - if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); - ogs_free(content_hosting_cache); - } - msaf_application_server_state_log(&as_state->purge_content_hosting_cache, "Purge Content Hosting Cache list"); - - } - } - - - if((response->status == 404) || (response->status == 413) || (response->status == 414) || (response->status == 415) || (response->status == 422) || (response->status == 500) || (response->status == 503)) { - char *error; - purge_resource_id_node_t *content_hosting_cache, *next = NULL; - cJSON *purge_cache_err = NULL; - if(response->http.content){ - purge_cache_err = cJSON_Parse(response->http.content); - char *txt = cJSON_Print(purge_cache_err); - ogs_debug("txt:%s", txt); - } - - if(response->status == 404) { - - ogs_error("Error message from the Application Server [%s] with response code [%d]: Cache not found\n", as_state->application_server->canonicalHostname, response->status); - } else if(response->status == 413) { - ogs_error("Error message from the Application Server [%s] with response code [%d]: Pay load too large\n", as_state->application_server->canonicalHostname, response->status); - } else if(response->status == 414) { - ogs_error("Error message from the Application Server [%s] with response code [%d]: URI too long\n", as_state->application_server->canonicalHostname, response->status); - } else if(response->status == 415) { - ogs_error("Error message from the Application Server [%s] with response code [%d]: Unsupported media type\n", as_state->application_server->canonicalHostname, response->status); - } else if(response->status == 422) { - ogs_error("Error message from the Application Server [%s] with response code [%d]: Unprocessable Entity\n", as_state->application_server->canonicalHostname, response->status); - } else if(response->status == 500) { - ogs_error("Error message from the Application Server [%s] with response code [%d]: Internal server error\n", as_state->application_server->canonicalHostname, response->status); - } else if(response->status == 503) { - ogs_error("Error message from the Application Server [%s] with response code [%d]: Service Unavailable\n", as_state->application_server->canonicalHostname, response->status); - } else { - - ogs_error("Application Server [%s] sent unrecognised response code [%d]", as_state->application_server->canonicalHostname, response->status); - } - - if (purge_node->purge_regex) { - error = ogs_msprintf("Application Server possibly encountered problem with regex %s", purge_node->purge_regex); - } else { - error = ogs_msprintf("Application Server unable to process the contained instructions"); - } - - - ogs_assert(true == nf_server_send_error( purge_node->m1_purge_info->m1_stream, - response->status, 3, &purge_node->m1_purge_info->m1_message, "Problem occured during cache purge", error, purge_cache_err, m1_contenthostingprovisioning_api, app_meta)); - - ogs_list_for_each_safe(&as_state->purge_content_hosting_cache, next, content_hosting_cache){ - if (purge_node->purge_regex) { - if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id) && !strcmp(content_hosting_cache->purge_regex, purge_node->purge_regex)) { - - ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); - ogs_debug("M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); - if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); - if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); - if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); - ogs_free(content_hosting_cache); - - } - } else if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id)) { - - ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); - ogs_debug("M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); - if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); - if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); - if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); - ogs_free(content_hosting_cache); - - } - } - ogs_free(error); - cJSON_Delete(purge_cache_err); - - } - - next_action_for_application_server(as_state); - break; - END - break; - - } - } else if (message.h.resource.component[1]) { - - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_POST) - - if (response->status == 201) { - - ogs_debug("[%s] Method [%s] with Response [%d] recieved for Content Hosting Configuration [%s]", message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); - - resource_id_node_t *content_hosting_configuration; - ogs_list_for_each(&as_state->upload_content_hosting_configurations,content_hosting_configuration) { - if(!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) - break; - } - if(content_hosting_configuration) { - - ogs_debug("Removing %s from upload_content_hosting_configurations", content_hosting_configuration->state); - ogs_list_remove(&as_state->upload_content_hosting_configurations, content_hosting_configuration); - ogs_debug("Adding %s to current_content_hosting_configurations",content_hosting_configuration->state); - ogs_list_add(as_state->current_content_hosting_configurations, content_hosting_configuration); - } - - } - if(response->status == 405){ - ogs_error("Content Hosting Configuration resource already exist at the specified path\n"); - } - if(response->status == 413){ - ogs_error("Payload too large\n"); - } - if(response->status == 414){ - ogs_error("URI too long\n"); - } - if(response->status == 415){ - ogs_error("Unsupported media type\n"); - } - if(response->status == 500){ - ogs_error("Internal server error\n"); - } - if(response->status == 503){ - ogs_error("Service unavailable\n"); - } - next_action_for_application_server(as_state); - break; - CASE(OGS_SBI_HTTP_METHOD_PUT) - if(response->status == 200 || response->status == 204) { - - ogs_debug("[%s] Method [%s] with Response [%d] recieved for Content Hosting Configuration [%s]", message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); - resource_id_node_t *content_hosting_configuration; - ogs_list_for_each(&as_state->upload_content_hosting_configurations,content_hosting_configuration){ - if(!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) - break; - } - if(content_hosting_configuration) { - - ogs_debug("Removing %s from upload_content_hosting_configurations", content_hosting_configuration->state); - ogs_free(content_hosting_configuration->state); - ogs_list_remove(&as_state->upload_content_hosting_configurations, content_hosting_configuration); - ogs_free(content_hosting_configuration); - } - - } - if(response->status == 404){ - ogs_error("Not Found\n"); - } - if(response->status == 413){ - ogs_error("Payload too large\n"); - } - if(response->status == 414){ - ogs_error("URI too long\n"); - } - if(response->status == 415){ - ogs_error("Unsupported Media Type\n"); - } - if(response->status == 500){ - ogs_error("Internal Server Error\n"); - } - if(response->status == 503){ - ogs_error("Service Unavailable\n"); - } - next_action_for_application_server(as_state); - break; - CASE(OGS_SBI_HTTP_METHOD_DELETE) - if(response->status == 204) { - - ogs_debug("[%s] Method [%s] with Response [%d] recieved for Content Hosting Configuration [%s]", message.h.resource.component[0], message.h.method, response->status,message.h.resource.component[1]); - - resource_id_node_t *content_hosting_configuration, *next = NULL; - resource_id_node_t *delete_content_hosting_configuration, *node = NULL; - - if(as_state->current_content_hosting_configurations) { - - ogs_list_for_each_safe(as_state->current_content_hosting_configurations, next, content_hosting_configuration){ - - if(!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) - break; - } - } - - if(content_hosting_configuration) { - - msaf_application_server_state_log(as_state->current_content_hosting_configurations, "Current Content Hosting Configurations"); - - ogs_debug("Removing %s from current_content_hosting_configurations", content_hosting_configuration->state); - ogs_free(content_hosting_configuration->state); - ogs_list_remove(as_state->current_content_hosting_configurations, content_hosting_configuration); - ogs_free(content_hosting_configuration); - msaf_application_server_state_log(as_state->current_content_hosting_configurations, "Current Content Hosting Configurations"); - } - - ogs_list_for_each_safe(&as_state->delete_content_hosting_configurations, node, delete_content_hosting_configuration) { - - if (!strcmp(delete_content_hosting_configuration->state, message.h.resource.component[1])) { - - msaf_application_server_state_log(&as_state->delete_content_hosting_configurations, "Delete Content Hosting Configurations"); - - ogs_debug("Destroying Content Hosting Configuration: %s", delete_content_hosting_configuration->state); - ogs_free(delete_content_hosting_configuration->state); - ogs_list_remove(&as_state->delete_content_hosting_configurations, delete_content_hosting_configuration); - ogs_free(delete_content_hosting_configuration); - - msaf_application_server_state_log(&as_state->delete_content_hosting_configurations, "Delete Content Hosting Configurations"); - } - } - - } - if(response->status == 404){ - ogs_error("Not Found\n"); - } - if(response->status == 413){ - ogs_error("Payload too large\n"); - } - if(response->status == 414){ - ogs_error("URI too long\n"); - } - if(response->status == 415){ - ogs_error("Unsupported Media Type\n"); - } - if(response->status == 500){ - ogs_error("Internal Server Error\n"); - } - if(response->status == 503){ - ogs_error("Service Unavailable\n"); - } - next_action_for_application_server(as_state); - break; - DEFAULT - ogs_error("Unknown M3 Content Hosting Configuration operation [%s]", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Content Hosting Configuration operation", message.h.resource.component[1], NULL, NULL, app_meta)); - break; - END - break; - } else { - cJSON *entry; - cJSON *chc_array = cJSON_Parse(response->http.content); - resource_id_node_t *current_chc; - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_GET) - - if(response->status == 200) { - - ogs_debug("[%s] Method [%s] with Response [%d] for Content Hosting Configuration operation [%s]", - message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); - - if (as_state->current_content_hosting_configurations == NULL) { - as_state->current_content_hosting_configurations = ogs_calloc(1,sizeof(*as_state->current_content_hosting_configurations)); - ogs_assert(as_state->current_content_hosting_configurations); - ogs_list_init(as_state->current_content_hosting_configurations); - - } else { - resource_id_node_t *next, *node; - ogs_list_for_each_safe(as_state->current_content_hosting_configurations, next, node) { - ogs_free(node->state); - ogs_list_remove(as_state->current_content_hosting_configurations, node); - ogs_free(node); - } - } - cJSON_ArrayForEach(entry, chc_array) { - char *id = strrchr(entry->valuestring, '/'); - if (id == NULL) { - id = entry->valuestring; - } else { - id++; - } - current_chc = ogs_calloc(1, sizeof(*current_chc)); - current_chc->state = ogs_strdup(id); - ogs_debug("Adding [%s] to the current Content Hosting Configuration list",current_chc->state); - ogs_list_add(as_state->current_content_hosting_configurations, current_chc); - } - - cJSON_Delete(chc_array); - } - if (response->status == 500){ - ogs_error("Received Internal Server error\n"); - } - if (response->status == 503) { - ogs_error("Service Unavailable\n"); - } - next_action_for_application_server(as_state); - break; - DEFAULT - char *err; - ogs_error("Unknown M3 Content Hosting Configuration operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); - asprintf(&err, "Unknown M3 Content Hosting Configuration operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Content Hosting Configuration operation", err, NULL, NULL, app_meta)); - - break; - END - break; - } - next_action_for_application_server(as_state); - - break; - - CASE("certificates") - - msaf_application_server_state_node_t *as_state; - as_state = e->application_server_state; - ogs_assert(as_state); - if (message.h.resource.component[1]) { - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_POST) - if(response->status == 201) { - - ogs_debug("[%s] Method [%s] with Response [%d] recieved for certificate [%s]", message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); - - resource_id_node_t *certificate; - - //Iterate upload_certs and find match strcmp resource component 0 - ogs_list_for_each(&as_state->upload_certificates,certificate){ - if(!strcmp(certificate->state, message.h.resource.component[1])) - break; - } - if(certificate) { - - ogs_debug("Removing certificate [%s] from upload_certificates", certificate->state); - - ogs_list_remove(&as_state->upload_certificates, certificate); - - ogs_debug("Adding certificate [%s] to current_certificates", certificate->state); - - ogs_list_add(as_state->current_certificates, certificate); - // ogs_free(upload_cert_id); - } - } - if(response->status == 405){ - ogs_error("Server Certificate resource already exist at the specified path\n"); - } - if(response->status == 413){ - ogs_error("Payload too large\n"); - } - if(response->status == 414){ - ogs_error("URI too long\n"); - } - if(response->status == 415){ - ogs_error("Unsupported media type\n"); - } - if(response->status == 500){ - ogs_error("Internal server error\n"); - } - if(response->status == 503){ - ogs_error("Service unavailable\n"); - } - next_action_for_application_server(as_state); - break; - CASE(OGS_SBI_HTTP_METHOD_PUT) - if(response->status == 200 || response->status == 204) { - - ogs_debug("[%s] Method [%s] with Response [%d] recieved for certificate [%s]", message.h.resource.component[0], message.h.method, response->status,message.h.resource.component[1]); - - resource_id_node_t *certificate; - - msaf_application_server_state_log(&as_state->upload_certificates, "Upload Certificates"); - - //Iterate upload_certs and find match strcmp resource component 0 - ogs_list_for_each(&as_state->upload_certificates,certificate){ - - if(!strcmp(certificate->state, message.h.resource.component[1])) - break; - } - - if(!certificate){ - ogs_debug("Certificate %s not found in upload certificates", message.h.resource.component[1]); - } else { - ogs_debug("Removing certificate [%s] from upload_certificates", certificate->state); - ogs_free(certificate->state); - - ogs_list_remove(&as_state->upload_certificates, certificate); - ogs_free(certificate); - } - } - if(response->status == 404){ - ogs_error("Not Found\n"); - } - if(response->status == 413){ - ogs_error("Payload too large\n"); - } - if(response->status == 414){ - ogs_error("URI too long\n"); - } - if(response->status == 415){ - ogs_error("Unsupported Media Type\n"); - } - if(response->status == 500){ - ogs_error("Internal Server Error\n"); - } - if(response->status == 503){ - ogs_error("Service Unavailable\n"); - } - next_action_for_application_server(as_state); - break; - CASE(OGS_SBI_HTTP_METHOD_DELETE) - if(response->status == 204) { - - ogs_debug("[%s] Method [%s] with Response [%d] recieved for Certificate [%s]", message.h.resource.component[0], message.h.method, response->status,message.h.resource.component[1]); - - resource_id_node_t *certificate, *next = NULL; - resource_id_node_t *delete_certificate, *node = NULL; - - if(as_state->current_certificates) { - ogs_list_for_each_safe(as_state->current_certificates, next, certificate){ - - if(!strcmp(certificate->state, message.h.resource.component[1])) - break; - } - } - - if(certificate) { - - msaf_application_server_state_log(as_state->current_certificates, "Current Certificates"); - - ogs_debug("Removing certificate [%s] from current_certificates", certificate->state); - ogs_free(certificate->state); - - ogs_list_remove(as_state->current_certificates, certificate); - ogs_free(certificate); - msaf_application_server_state_log(as_state->current_certificates, "Current Certificates"); - } - - - ogs_list_for_each_safe(&as_state->delete_certificates, node, delete_certificate){ - - if(!strcmp(delete_certificate->state, message.h.resource.component[1])) { - msaf_application_server_state_log(&as_state->delete_certificates, "Delete Certificates"); - - ogs_debug("Destroying Certificate: %s", delete_certificate->state); - ogs_free(delete_certificate->state); - ogs_list_remove(&as_state->delete_certificates, delete_certificate); - ogs_free(delete_certificate); - msaf_application_server_state_log(&as_state->delete_certificates, "Delete Certificates"); - - } - } - } - if(response->status == 404){ - ogs_error("Not Found\n"); - } - if(response->status == 413){ - ogs_error("Payload too large\n"); - } - if(response->status == 414){ - ogs_error("URI too long\n"); - } - if(response->status == 415){ - ogs_error("Unsupported Media Type\n"); - } - if(response->status == 500){ - ogs_error("Internal Server Error\n"); - } - if(response->status == 503){ - ogs_error("Service Unavailable\n"); - } - next_action_for_application_server(as_state); - break; - DEFAULT - ogs_error("Unknown M3 certificate operation [%s]", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 certificate operation.", message.h.resource.component[1], NULL, NULL, app_meta)); - break; - END - break; - } else { - cJSON *entry; - cJSON *cert_array = cJSON_Parse(response->http.content); - resource_id_node_t *current_cert; - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_GET) - - if(response->status == 200) { - - ogs_debug("[%s] Method [%s] with Response [%d] received", - message.h.resource.component[0], message.h.method, response->status); - - if (as_state->current_certificates == NULL) { - as_state->current_certificates = ogs_calloc(1,sizeof(*as_state->current_certificates)); - ogs_assert(as_state->current_certificates); - ogs_list_init(as_state->current_certificates); - - } else { - resource_id_node_t *next, *node; - ogs_list_for_each_safe(as_state->current_certificates, next, node) { - - ogs_debug("Removing certificate [%s] from current_certificates", node->state); - - ogs_free(node->state); - ogs_list_remove(as_state->current_certificates, node); - ogs_free(node); - } - } - cJSON_ArrayForEach(entry, cert_array) { - char *id = strrchr(entry->valuestring, '/'); - if (id == NULL) { - id = entry->valuestring; - } else { - id++; - } - current_cert = ogs_calloc(1, sizeof(*current_cert)); - current_cert->state = ogs_strdup(id); - ogs_debug("Adding certificate [%s] to Current certificates", current_cert->state); - ogs_list_add(as_state->current_certificates, current_cert); - } - - cJSON_Delete(cert_array); - } - if (response->status == 500){ - ogs_error("Received Internal Server error"); - } - if (response->status == 503) { - ogs_error("Service Unavailable"); - } - next_action_for_application_server(as_state); - break; - DEFAULT - char *err; - ogs_error("Unknown M3 certificate operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); - asprintf(&err, "Unsupported M3 Certificate operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Certificate operation", err, NULL, NULL, app_meta)); - - break; - END - break; - } - next_action_for_application_server(as_state); - - break; - - DEFAULT - ogs_error("Unknown M3 operation [%s]", message.h.resource.component[0]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unsupported M3 operation", message.h.resource.component[0], NULL, NULL, app_meta)); - break; - END - break; - + CASE(OGS_SBI_SERVICE_NAME_NNRF_NFM) SWITCH(message.h.resource.component[0]) diff --git a/src/5gmsaf/msaf-sm.h b/src/5gmsaf/msaf-sm.h index 5a3d53d..14fae67 100644 --- a/src/5gmsaf/msaf-sm.h +++ b/src/5gmsaf/msaf-sm.h @@ -23,6 +23,21 @@ void msaf_state_final(ogs_fsm_t *s, msaf_event_t *e); void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e); void msaf_state_exception(ogs_fsm_t *s, msaf_event_t *e); +void msaf_m1_state_initial(ogs_fsm_t *s, msaf_event_t *e); +void msaf_m1_state_final(ogs_fsm_t *s, msaf_event_t *e); +void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e); +void msaf_m1_state_exception(ogs_fsm_t *s, msaf_event_t *e); + +void msaf_m5_state_initial(ogs_fsm_t *s, msaf_event_t *e); +void msaf_m5_state_final(ogs_fsm_t *s, msaf_event_t *e); +void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e); +void msaf_m5_state_exception(ogs_fsm_t *s, msaf_event_t *e); + +void msaf_maf_mgmt_state_initial(ogs_fsm_t *s, msaf_event_t *e); +void msaf_maf_mgmt_state_final(ogs_fsm_t *s, msaf_event_t *e); +void msaf_maf_mgmt_state_functional(ogs_fsm_t *s, msaf_event_t *e); +void msaf_maf_mgmt_state_exception(ogs_fsm_t *s, msaf_event_t *e); + #define msaf_sm_debug(__pe) \ ogs_debug("%s(): %s", __func__, msaf_event_get_name(__pe)) From cdb6644e723c128623c847587c9600256070541a Mon Sep 17 00:00:00 2001 From: deva Date: Tue, 14 Mar 2023 13:26:39 +0000 Subject: [PATCH 24/48] Modified to return 204 on M1 retrieveServerCertificate request when the certificate has been reserved but not uploaded. --- src/5gmsaf/msaf-m1-sm.c | 23 +- src/5gmsaf/msaf-sm.c | 883 ---------------------------------------- 2 files changed, 12 insertions(+), 894 deletions(-) diff --git a/src/5gmsaf/msaf-m1-sm.c b/src/5gmsaf/msaf-m1-sm.c index a64d202..543af7b 100644 --- a/src/5gmsaf/msaf-m1-sm.c +++ b/src/5gmsaf/msaf-m1-sm.c @@ -488,10 +488,10 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) provisioning_session_cert = ogs_hash_get(msaf_provisioning_session->certificate_map, message.h.resource.component[3], OGS_HASH_KEY_STRING); cert = server_cert_retrieve(message.h.resource.component[3]); if(!cert || !provisioning_session_cert) { - ogs_error("unable to retrieve certificate [%s]", message.h.resource.component[3]); + ogs_error("Certificate [%s] management problem", message.h.resource.component[3]); char *err = NULL; - asprintf(&err,"Unable to retrieve Certificate not yet available"); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate not yet available.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + asprintf(&err,"Certificate [%s] management problem", message.h.resource.component[3]); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); return; } @@ -513,10 +513,11 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } else if(cert->return_code == 8){ - char *err = NULL; - asprintf(&err,"Certificate [%s] not yet available.", cert->id); - ogs_error("Certificate [%s] not yet available.", cert->id); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate not yet available.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + ogs_sbi_response_t *response; + response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_servercertificatesprovisioning_api, app_meta); + nf_server_populate_response(response, 0, NULL, 204); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); } else { char *err = NULL; asprintf(&err,"Certificate [%s] management problem.", cert->id); @@ -897,11 +898,11 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_assert(true == ogs_sbi_server_send_response(stream, response)); msaf_certificate_free(cert); } else { + ogs_error("Certificate [%s] management problem", message.h.resource.component[3]); char *err = NULL; - ogs_error("Method [%s]: Unable to retrieve certificate [%s]", message.h.method, message.h.resource.component[3]); - asprintf(&err,"Method [%s]: Unable to retrieve certificate [%s]", message.h.method, message.h.resource.component[3]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Unable to retrieve certificate.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - + asprintf(&err,"Certificate [%s] management problem", message.h.resource.component[3]); + ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + return; } } else { methods = ogs_msprintf("%s",OGS_SBI_HTTP_METHOD_POST); diff --git a/src/5gmsaf/msaf-sm.c b/src/5gmsaf/msaf-sm.c index e21ca3d..c0d3e6d 100644 --- a/src/5gmsaf/msaf-sm.c +++ b/src/5gmsaf/msaf-sm.c @@ -143,889 +143,6 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_NOT_FOUND, 1, NULL, "Not Found.", error, NULL, NULL, app_meta)); ogs_free(error); } -<<<<<<< Updated upstream - SWITCH(message.h.resource.component[0]) - - CASE("provisioning-sessions") - SWITCH(message.h.method) - CASE(OGS_SBI_HTTP_METHOD_POST) - - if (message.h.resource.component[1] && message.h.resource.component[2] && message.h.resource.component[3]) { - msaf_provisioning_session_t *msaf_provisioning_session; - - if (!strcmp(message.h.resource.component[2],"content-hosting-configuration") && !strcmp(message.h.resource.component[3],"purge")) { - ogs_hash_index_t *hi; - for (hi = ogs_hash_first(request->http.headers); - hi; hi = ogs_hash_next(hi)) { - if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { - if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/x-www-form-urlencoded")) { - char *err = NULL; - char *type = NULL; - type = (char *)ogs_hash_this_val(hi); - ogs_error("Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); - asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); - - ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - ogs_sbi_message_free(&message); - return; - - } - } - } - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if(msaf_provisioning_session) { - // process the POST body - purge_resource_id_node_t *purge_cache; - msaf_application_server_state_node_t *as_state; - assigned_provisioning_sessions_node_t *assigned_provisioning_sessions_resource; - m1_purge_information_t *m1_purge_info = ogs_calloc(1, sizeof(m1_purge_information_t)); - m1_purge_info->m1_stream = stream; - m1_purge_info->m1_message = message; - - ogs_list_for_each(&msaf_provisioning_session->msaf_application_server_state_nodes, as_state) { - if(as_state->application_server && as_state->application_server->canonicalHostname) { - ogs_list_for_each(&as_state->assigned_provisioning_sessions,assigned_provisioning_sessions_resource){ - if(!strcmp(assigned_provisioning_sessions_resource->assigned_provisioning_session->provisioningSessionId, msaf_provisioning_session->provisioningSessionId)) { - - purge_cache = ogs_calloc(1, sizeof(purge_resource_id_node_t)); - ogs_assert(purge_cache); - purge_cache->provisioning_session_id = ogs_strdup(assigned_provisioning_sessions_resource->assigned_provisioning_session->provisioningSessionId); - - purge_cache->m1_purge_info = m1_purge_info; - m1_purge_info->refs++; - if(request->http.content) - purge_cache->purge_regex = ogs_strdup(request->http.content); - else - purge_cache->purge_regex = NULL; - - if (ogs_list_first(&as_state->purge_content_hosting_cache) == NULL) - ogs_list_init(&as_state->purge_content_hosting_cache); - - ogs_list_add(&as_state->purge_content_hosting_cache, purge_cache); - } else { - ogs_error("Provisioning Session [%s] is not assigned to an Application Server", message.h.resource.component[1]); - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] is not assigned to an Application Server", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session is not assigned to an Application Server.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - } - } - } else { - ogs_error("Provisioning Session [%s]: Unable to get information about Application Server", message.h.resource.component[1]); - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] : Unable to get information about Application Server", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Unable to get information about Application Server", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - } - - next_action_for_application_server(as_state); - } - if (m1_purge_info->refs == 0) { - ogs_free(m1_purge_info); - // Send 204 back to M1 client - ogs_sbi_response_t *response; - response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_contenthostingprovisioning_api, app_meta); - nf_server_populate_response(response, 0, NULL, 204); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - } - } else { - ogs_error("Unable to retrieve the Provisioning Session [%s]", message.h.resource.component[1]); - char *err = NULL; - asprintf(&err,"Provisioning session [%s] does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - - } - - } - - } else if (message.h.resource.component[1] && message.h.resource.component[2]) { - msaf_provisioning_session_t *msaf_provisioning_session; - if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if(msaf_provisioning_session) { - // process the POST body - cJSON *entry; - int rv; - cJSON *chc; - cJSON *content_hosting_config = cJSON_Parse(request->http.content); - char *txt = cJSON_Print(content_hosting_config); - ogs_debug("body:%s", request->http.content); - ogs_debug("txt:%s", txt); - - cJSON_ArrayForEach(entry, content_hosting_config) { - if(!strcmp(entry->string, "entryPointPath")){ - if(!uri_relative_check(entry->valuestring)) { - char *err = NULL; - asprintf(&err,"While creating the Content Hosting Configuration for the Provisioning Session [%s], entryPointPath does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring ); - ogs_error("While creating the Content Hosting Configuration for the Provisioning Session [%s], entryPointPath does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring); - - ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - - cJSON_Delete(content_hosting_config); - break; - } - } - } - - if(msaf_provisioning_session->contentHostingConfiguration) { - OpenAPI_content_hosting_configuration_free(msaf_provisioning_session->contentHostingConfiguration); - msaf_provisioning_session->contentHostingConfiguration = NULL; - - } - - if (msaf_provisioning_session->serviceAccessInformation) { - OpenAPI_service_access_information_resource_free(msaf_provisioning_session->serviceAccessInformation); - msaf_provisioning_session->serviceAccessInformation = NULL; - } - - rv = msaf_distribution_create(content_hosting_config, msaf_provisioning_session); - - if(rv){ - - ogs_debug("Content Hosting Configuration created successfully"); - if (msaf_application_server_state_set_on_post(msaf_provisioning_session)) { - chc = msaf_get_content_hosting_configuration_by_provisioning_session_id(message.h.resource.component[1]); - if (chc != NULL) { - char *text; - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, NULL, m1_contentprotocolsdiscovery_api, app_meta); - text = cJSON_Print(chc); - nf_server_populate_response(response, strlen(text), text, 201); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - cJSON_Delete(chc); - cJSON_Delete(content_hosting_config); - } else { - char *err = NULL; - ogs_error("Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); - asprintf(&err,"Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - } - } else { - char *err = NULL; - ogs_error("Verification error on Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); - asprintf(&err,"Verification error on Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 400, 2, &message, "Bad Content Hosting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - } - } else { - char *err = NULL; - - ogs_error("Failed to populate Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); - asprintf(&err,"Creation of the Content Hosting Configuration failed for the Provisioning Session [%s]", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 500, 2, &message, "Creation of the Content Hosting Configuration failed.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - } - - } else { - char *err = NULL; - asprintf(&err,"Provisioning session [%s]does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - - - } - - } - if (!strcmp(message.h.resource.component[2],"certificates")) { - ogs_info("POST certificates"); - ogs_hash_index_t *hi; - char *canonical_domain_name; - char *cert; - int csr = 0; - - for (hi = ogs_hash_first(request->http.params); - hi; hi = ogs_hash_next(hi)) { - if (!ogs_strcasecmp(ogs_hash_this_key(hi), "csr")) { - csr = 1; - break; - } - } - - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if (msaf_provisioning_session) { - msaf_application_server_node_t *msaf_as = NULL; - msaf_as = ogs_list_first(&msaf_self()->config.applicationServers_list); - canonical_domain_name = msaf_as->canonicalHostname; - ogs_info("canonical_domain_name: %s", canonical_domain_name); - - if (csr) { - msaf_certificate_t *csr_cert; - char *location; - int m1_server_certificates_response_max_age; - csr_cert = server_cert_new("newcsr", canonical_domain_name); - ogs_hash_set(msaf_provisioning_session->certificate_map, ogs_strdup(csr_cert->id), OGS_HASH_KEY_STRING, ogs_strdup(csr_cert->id)); - ogs_sbi_response_t *response; - location = ogs_msprintf("%s/%s", request->h.uri, csr_cert->id); - if(csr_cert->cache_control_max_age){ - m1_server_certificates_response_max_age = csr_cert->cache_control_max_age; - } else { - m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; - } - response = nf_server_new_response(location, "application/x-pem-file", csr_cert->last_modified, csr_cert->server_certificate_hash, m1_server_certificates_response_max_age, NULL, m1_servercertificatesprovisioning_api, app_meta); - - nf_server_populate_response(response, strlen(csr_cert->certificate), ogs_strdup(csr_cert->certificate), 200); - - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - ogs_free(location); - msaf_certificate_free(csr_cert); - - return; - } - - if (ogs_list_first(&msaf_provisioning_session->msaf_application_servers) == NULL) { - ogs_list_init(&msaf_provisioning_session->msaf_application_server_state_nodes); - ogs_list_add(&msaf_provisioning_session->msaf_application_server_state_nodes, msaf_as); - } - - cert = check_in_cert_list(canonical_domain_name); - if (cert != NULL) { - ogs_sbi_response_t *response; - char *location; - - ogs_hash_set(msaf_provisioning_session->certificate_map, ogs_strdup(cert), OGS_HASH_KEY_STRING, ogs_strdup(cert)); - - location = ogs_msprintf("%s/%s", request->h.uri, cert); - response = nf_server_new_response(location, NULL, 0, NULL, 0, NULL, m1_servercertificatesprovisioning_api, app_meta); - nf_server_populate_response(response, 0, NULL, 200); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - ogs_free(location); - } else { - msaf_certificate_t *new_cert; - int m1_server_certificates_response_max_age; - ogs_sbi_response_t *response; - char *location; - new_cert = server_cert_new("newcert", canonical_domain_name); - ogs_hash_set(msaf_provisioning_session->certificate_map, ogs_strdup(new_cert->id), OGS_HASH_KEY_STRING, ogs_strdup(new_cert->id)); - - location = ogs_msprintf("%s/%s", request->h.uri, new_cert->id); - if(new_cert->cache_control_max_age){ - m1_server_certificates_response_max_age = new_cert->cache_control_max_age; - } else { - m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; - } - response = nf_server_new_response(location, NULL, new_cert->last_modified, new_cert->server_certificate_hash, m1_server_certificates_response_max_age, NULL, m1_servercertificatesprovisioning_api, app_meta); - nf_server_populate_response(response, 0, NULL, 200); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - ogs_free(location); - msaf_certificate_free(new_cert); - } - } else { - char *err = NULL; - asprintf(&err,"Provisioning session [%s] does not exists.", message.h.resource.component[1]); - ogs_error("Provisioning session [%s] does not exists.", message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - } - } - } else { - cJSON *entry; - cJSON *prov_sess = cJSON_Parse(request->http.content); - cJSON *provisioning_session; - char *provisioning_session_type, *external_app_id, *asp_id = NULL; - msaf_provisioning_session_t *msaf_provisioning_session; - - ogs_debug("createProvisioningSession: received=\"%s\"", request->http.content); - - entry = cJSON_GetObjectItemCaseSensitive(prov_sess, "provisioningSessionType"); - if (!entry) { - const char *err = "createProvisioningSession: \"provisioningSessionType\" is not present"; - ogs_error(err); - ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); - break; - } - if (!cJSON_IsString(entry)) { - const char *err = "createProvisioningSession: \"provisioningSessionType\" is not a string"; - ogs_error(err); - ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); - break; - } - provisioning_session_type = entry->valuestring; - - entry = cJSON_GetObjectItemCaseSensitive(prov_sess, "externalApplicationId"); - if (!entry) { - const char *err = "createProvisioningSession: \"externalApplicationId\" is not present"; - ogs_error(err); - ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); - break; - } - if (!cJSON_IsString(entry)) { - const char *err = "createProvisioningSession: \"externalApplicationId\" is not a string"; - ogs_error(err); - ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); - break; - } - external_app_id = entry->valuestring; - - entry = cJSON_GetObjectItemCaseSensitive(prov_sess, "aspId"); - if (entry) { - if (!cJSON_IsString(entry)) { - const char *err = "createProvisioningSession: \"aspId\" is not a string"; - ogs_error(err); - ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); - break; - } - asp_id = entry->valuestring; - } - - msaf_provisioning_session = msaf_provisioning_session_create(provisioning_session_type, asp_id, external_app_id); - - provisioning_session = msaf_provisioning_session_get_json(msaf_provisioning_session->provisioningSessionId); - if (provisioning_session != NULL) { - ogs_sbi_response_t *response; - char *text; - char *location; - text = cJSON_Print(provisioning_session); - if (request->h.uri[strlen(request->h.uri)-1] != '/') { - location = ogs_msprintf("%s/%s", request->h.uri,msaf_provisioning_session->provisioningSessionId); - } else { - location = ogs_msprintf("%s%s", request->h.uri,msaf_provisioning_session->provisioningSessionId); - } - response = nf_server_new_response(location, "application/json", msaf_provisioning_session->provisioningSessionReceived, msaf_provisioning_session->provisioningSessionHash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, m1_provisioningsession_api, app_meta); - - nf_server_populate_response(response, strlen(text), text, 201); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - ogs_free(location); - cJSON_Delete(provisioning_session); - cJSON_Delete(prov_sess); - } else { - char *err = NULL; - asprintf(&err,"Creation of the Provisioning session failed."); - ogs_error("Creation of the Provisioning session failed."); - ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); - } - } - - break; - - CASE(OGS_SBI_HTTP_METHOD_GET) - if (message.h.resource.component[1] && message.h.resource.component[2] && message.h.resource.component[3]) { - if (!strcmp(message.h.resource.component[2],"certificates") ) { - msaf_provisioning_session_t *msaf_provisioning_session; - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if (msaf_provisioning_session) { - msaf_certificate_t *cert; - ogs_sbi_response_t *response; - const char *provisioning_session_cert; - provisioning_session_cert = ogs_hash_get(msaf_provisioning_session->certificate_map, message.h.resource.component[3], OGS_HASH_KEY_STRING); - cert = server_cert_retrieve(message.h.resource.component[3]); - if(!cert || !provisioning_session_cert) { - ogs_error("unable to retrieve certificate [%s]", message.h.resource.component[3]); - char *err = NULL; - asprintf(&err,"Unable to retrieve Certificate not yet available"); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate not yet available.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - return; - } - - if(!cert->return_code) { - int m1_server_certificates_response_max_age; - if(cert->cache_control_max_age){ - m1_server_certificates_response_max_age = cert->cache_control_max_age; - } else { - m1_server_certificates_response_max_age = msaf_self()->config.server_response_cache_control->m1_server_certificates_response_max_age; - } - response = nf_server_new_response(NULL, "application/x-pem-file", cert->last_modified, cert->server_certificate_hash, m1_server_certificates_response_max_age, NULL, m1_servercertificatesprovisioning_api, app_meta); - nf_server_populate_response(response, strlen(cert->certificate), ogs_strdup(cert->certificate), 200); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - } else if(cert->return_code == 4){ - char *err = NULL; - asprintf(&err,"Certificate [%s] does not exists.", cert->id); - ogs_error("Certificate [%s] does not exists.", cert->id); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - - } else if(cert->return_code == 8){ - char *err = NULL; - asprintf(&err,"Certificate [%s] not yet available.", cert->id); - ogs_error("Certificate [%s] not yet available.", cert->id); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate not yet available.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - } else { - char *err = NULL; - asprintf(&err,"Certificate [%s] management problem.", cert->id); - ogs_error("Certificate [%s] management problem.", cert->id); - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - } - msaf_certificate_free(cert); - - } else { - char *err = NULL; - asprintf(&err,"Provisioning session [%s] is not available.", message.h.resource.component[1]); - ogs_error("Provisioning session [%s] is not available.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - } - } - } else if (message.h.resource.component[1] && message.h.resource.component[2]) { - msaf_provisioning_session_t *msaf_provisioning_session; - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { - if(msaf_provisioning_session) { - cJSON *chc; - chc = msaf_get_content_hosting_configuration_by_provisioning_session_id(message.h.resource.component[1]); - if (chc != NULL) { - ogs_sbi_response_t *response; - char *text; - text = cJSON_Print(chc); - - response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, NULL, m1_contenthostingprovisioning_api, app_meta); - ogs_assert(response); - nf_server_populate_response(response, strlen(text), text, 200); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - - cJSON_Delete(chc); - } else { - char *err = NULL; - ogs_error("Provisioning Session [%s]: Unable to retrieve the Content Hosting Configuration", message.h.resource.component[1]); - asprintf(&err,"Provisioning Session [%s]: Unable to retrieve the Content Hosting Configuration", message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - } - - } else { - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - - } - - } else if (!strcmp(message.h.resource.component[2],"protocols")) { - if(msaf_provisioning_session) { - ogs_sbi_response_t *response; - ogs_info("CONTENT_PROTOCOLS_DISCOVERY_JSON: %s", CONTENT_PROTOCOLS_DISCOVERY_JSON); - response = nf_server_new_response(NULL, "application/json", CONTENT_PROTOCOLS_DISCOVERY_JSON_TIME, CONTENT_PROTOCOLS_DISCOVERY_JSON_HASH, msaf_self()->config.server_response_cache_control->m1_content_protocols_response_max_age, NULL, m1_contentprotocolsdiscovery_api, app_meta); - ogs_assert(response); - nf_server_populate_response(response, strlen(CONTENT_PROTOCOLS_DISCOVERY_JSON), ogs_strdup(CONTENT_PROTOCOLS_DISCOVERY_JSON), 200); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - } else { - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contentprotocolsdiscovery_api, app_meta)); - } - } - } else if (message.h.resource.component[1]) { - msaf_provisioning_session_t *msaf_provisioning_session = NULL; - cJSON *provisioning_session = NULL; - - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - - provisioning_session = msaf_provisioning_session_get_json(message.h.resource.component[1]); - - if (provisioning_session && msaf_provisioning_session && !msaf_provisioning_session->marked_for_deletion) { - ogs_sbi_response_t *response; - char *text; - text = cJSON_Print(provisioning_session); - - response = nf_server_new_response(NULL, "application/json", msaf_provisioning_session->provisioningSessionReceived, msaf_provisioning_session->provisioningSessionHash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, m1_provisioningsession_api, app_meta); - - nf_server_populate_response(response, strlen(text), text, 200); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - cJSON_Delete(provisioning_session); - - } else { - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] is not available.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] is not available.", message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL, m1_provisioningsession_api, app_meta)); - } - } - break; - - CASE(OGS_SBI_HTTP_METHOD_PUT) - if (message.h.resource.component[1] && message.h.resource.component[2]) { - - ogs_info("PUT: %s", message.h.resource.component[1]); - msaf_provisioning_session_t *msaf_provisioning_session; - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if(msaf_provisioning_session) { - ogs_info("PUT: with msaf_provisioning_session: %s", message.h.resource.component[1]); - if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { - - // process the POST body - cJSON *entry; - int rv; - cJSON *content_hosting_config = cJSON_Parse(request->http.content); - char *txt = cJSON_Print(content_hosting_config); - ogs_debug("txt:%s", txt); - - cJSON_ArrayForEach(entry, content_hosting_config) { - if(!strcmp(entry->string, "entryPointPath")){ - if(!uri_relative_check(entry->valuestring)) { - char *err = NULL; - asprintf(&err,"While updating the Content Hosting Configuration for the Provisioning Session [%s], Entry Point Path does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring ); - ogs_error("While updating the Content Hosting Configuration for the provisioning Session [%s], Entry Point Path does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring); - - ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - - cJSON_Delete(content_hosting_config); - break; - } - } - } - if(msaf_provisioning_session->contentHostingConfiguration) { - OpenAPI_content_hosting_configuration_free(msaf_provisioning_session->contentHostingConfiguration); - msaf_provisioning_session->contentHostingConfiguration = NULL; - } - - if (msaf_provisioning_session->serviceAccessInformation) { - OpenAPI_service_access_information_resource_free(msaf_provisioning_session->serviceAccessInformation); - msaf_provisioning_session->serviceAccessInformation = NULL; - } - - rv = msaf_distribution_create(content_hosting_config, msaf_provisioning_session); - if(rv){ - - msaf_application_server_state_update(msaf_provisioning_session); - - ogs_debug("Content Hosting Configuration updated successfully"); - - ogs_sbi_response_t *response; - response = ogs_sbi_response_new(); - response->status = 204; - ogs_sbi_header_set(response->http.headers, "Content-Type", "application/json"); - ogs_sbi_header_set(response->http.headers, "Location", request->h.uri); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - cJSON_Delete(content_hosting_config); - - } else { - char *err = NULL; - ogs_error("Provisioning Session [%s]: Failed to update the Content Hosting Configuration.", message.h.resource.component[1]); - asprintf(&err,"Provisioning Session [%s]: Update to Content Hosting Configuration failed.", message.h.resource.component[1]); - ogs_error("Update of the Content Hosting Configuration failed."); - - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Failed to update the contentHostingConfiguration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - - } - } - if (message.h.resource.component[1] && !strcmp(message.h.resource.component[2],"certificates") && message.h.resource.component[3]) { - char *cert_id; - char *cert; - int rv; - ogs_sbi_response_t *response; - msaf_provisioning_session_t *msaf_provisioning_session; - - { - ogs_hash_index_t *hi; - for (hi = ogs_hash_first(request->http.headers); - hi; hi = ogs_hash_next(hi)) { - if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { - if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/x-pem-file")) { - char *err = NULL; - char *type = NULL; - type = (char *)ogs_hash_this_val(hi); - ogs_error("Unsupported Media Type: received type: %s, should have been application/x-pem-file", type); - asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-pem-file", type); - - ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - ogs_sbi_message_free(&message); - return; - - } - } - } - } - - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - - if(msaf_provisioning_session) { - const char *provisioning_session_cert; - provisioning_session_cert = ogs_hash_get(msaf_provisioning_session->certificate_map, message.h.resource.component[3], OGS_HASH_KEY_STRING); - cert_id = message.h.resource.component[3]; - cert = ogs_strdup(request->http.content); - rv = server_cert_set(cert_id, cert); - // response = ogs_sbi_response_new(); - - if (rv == 0 && provisioning_session_cert){ - response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_servercertificatesprovisioning_api, app_meta); - nf_server_populate_response(response, 0, NULL, 204); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - } else if (rv == 3 && provisioning_session_cert ) { - - char *err = NULL; - ogs_error("A server certificate with id [%s] already exist", cert_id); - asprintf(&err,"A server certificate with id [%s] already exist", cert_id); - ogs_assert(true == nf_server_send_error(stream, 403, 3, &message, "A server certificate already exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - - } else if(rv == 4 || ! provisioning_session_cert) { - char *err = NULL; - ogs_error("Server certificate with id [%s] does not exist", cert_id); - asprintf(&err,"Server certificate with id [%s] does not exist", cert_id); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Server certificate does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - - } else if(rv == 5) { - char *err = NULL; - ogs_error("CSR was never generated for this certificate Id [%s]", cert_id); - asprintf(&err,"CSR was never generated for this certificate Id [%s]", cert_id); - ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "CSR was never generated for the certificate.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - } else if(rv == 6) { - char *err = NULL; - ogs_error("The public certificate [%s] provided does not match the key", cert_id); - asprintf(&err,"The public certificate [%s] provided does not match the key", cert_id); - ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "The public certificate provided does not match the key.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - } else { - char *err = NULL; - ogs_error("There was a certificate management problem for the certificate id [%s]", cert_id); - asprintf(&err,"There was a certificate management problem for the certificate id [%s].", cert_id); - - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "There was a certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - - - } - ogs_free(cert); - } - - } - - } else { - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - - } - - - } - break; - - CASE(OGS_SBI_HTTP_METHOD_DELETE) - - if (message.h.resource.component[1] && !strcmp(message.h.resource.component[2],"certificates") && message.h.resource.component[3]) { - ogs_sbi_response_t *response; - msaf_provisioning_session_t *provisioning_session = NULL; - provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if (provisioning_session) { - int rv; - rv = server_cert_delete(message.h.resource.component[3]); - if ((rv == 0) || (rv == 8)){ - response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_servercertificatesprovisioning_api, app_meta); - nf_server_populate_response(response, 0, NULL, 204); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - msaf_provisioning_session_certificate_hash_remove(message.h.resource.component[1], message.h.resource.component[3]); - - } else if (rv == 4 ) { - char *err = NULL; - asprintf(&err,"Certificate [%s] does not exist.", message.h.resource.component[3]); - ogs_error("Certificate [%s] does not exist.", message.h.resource.component[3]); - - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - - } else { - char *err = NULL; - asprintf(&err,"Certificate management problem for certificate [%s].", message.h.resource.component[3]); - ogs_error("Certificate management problem."); - - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - } - - } else { - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - - - } - } else if (message.h.resource.component[1] && message.h.resource.component[2]) { - msaf_provisioning_session_t *msaf_provisioning_session; - ogs_sbi_response_t *response; - if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { - msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if(msaf_provisioning_session){ - if(msaf_provisioning_session && msaf_provisioning_session->contentHostingConfiguration) { - msaf_delete_content_hosting_configuration(message.h.resource.component[1]); - OpenAPI_content_hosting_configuration_free(msaf_provisioning_session->contentHostingConfiguration); - msaf_provisioning_session->contentHostingConfiguration = NULL; - response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_contenthostingprovisioning_api, app_meta); - ogs_assert(response); - nf_server_populate_response(response, 0, NULL, 204); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - break; - } else { - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] has no Content Hosting Configuration.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] has no Content Hosting Configuration.", message.h.resource.component[1] ); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Content Hosting Configuration does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - } - } else { - char *err = NULL; - asprintf(&err,"Provisioning Session [%s] does not exists.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] does not exists.", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - } - - } - - } else if (message.h.resource.component[1]) { - ogs_sbi_response_t *response; - msaf_provisioning_session_t *provisioning_session = NULL; - provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if(!provisioning_session || provisioning_session->marked_for_deletion){ - char *err = NULL; - asprintf(&err,"Provisioning session [%s] either not found or already marked for deletion.", message.h.resource.component[1]); - - ogs_error("Provisioning session [%s] either not found or already marked for deletion.",message.h.resource.component[1]); - - ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session either not found or already marked for deletion.", err, NULL, m1_provisioningsession_api, app_meta)); - - } else { - provisioning_session->marked_for_deletion = 1; - response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_provisioningsession_api, app_meta); - ogs_assert(response); - nf_server_populate_response(response, 0, NULL, 202); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - msaf_delete_content_hosting_configuration(message.h.resource.component[1]); - msaf_delete_certificate(message.h.resource.component[1]); - msaf_context_provisioning_session_free(provisioning_session); - msaf_provisioning_session_hash_remove(message.h.resource.component[1]); - } - } - - break; - CASE(OGS_SBI_HTTP_METHOD_OPTIONS) - - if (!strcmp(message.h.resource.component[0],"provisioning-sessions")){ - ogs_sbi_response_t *response; - char *methods = NULL; - - if (message.h.resource.component[1]) { - msaf_provisioning_session_t *provisioning_session = NULL; - provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - if (provisioning_session) { - if (message.h.resource.component[2]) { - - - if (!strcmp(message.h.resource.component[2],"certificates")) { - if (message.h.resource.component[3]) { - msaf_certificate_t *cert; - cert = server_cert_retrieve(message.h.resource.component[3]); - if(cert){ - methods = ogs_msprintf("%s, %s, %s, %s",OGS_SBI_HTTP_METHOD_GET, OGS_SBI_HTTP_METHOD_PUT, OGS_SBI_HTTP_METHOD_DELETE, OGS_SBI_HTTP_METHOD_OPTIONS); - response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_servercertificatesprovisioning_api, app_meta); - nf_server_populate_response(response, 0, NULL, 204); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - msaf_certificate_free(cert); - } else { - char *err = NULL; - ogs_error("Method [%s]: Unable to retrieve certificate [%s]", message.h.method, message.h.resource.component[3]); - asprintf(&err,"Method [%s]: Unable to retrieve certificate [%s]", message.h.method, message.h.resource.component[3]); - ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Unable to retrieve certificate.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - - } - } else { - methods = ogs_msprintf("%s",OGS_SBI_HTTP_METHOD_POST); - response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_servercertificatesprovisioning_api, app_meta); - nf_server_populate_response(response, 0, NULL, 204); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - } - - } else if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { - methods = ogs_msprintf("%s, %s, %s, %s, %s",OGS_SBI_HTTP_METHOD_POST, OGS_SBI_HTTP_METHOD_GET, OGS_SBI_HTTP_METHOD_PUT, OGS_SBI_HTTP_METHOD_DELETE, OGS_SBI_HTTP_METHOD_OPTIONS); - response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_contenthostingprovisioning_api, app_meta); - nf_server_populate_response(response, 0, NULL, 204); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - - } else { - char *err = NULL; - asprintf(&err,"Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[2]); - ogs_error("Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[2]); - ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Target not yet supported.", err, NULL, NULL, app_meta)); - } - } else { - methods = ogs_msprintf("%s, %s, %s", OGS_SBI_HTTP_METHOD_GET, OGS_SBI_HTTP_METHOD_DELETE, OGS_SBI_HTTP_METHOD_OPTIONS); - response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_provisioningsession_api, app_meta); - nf_server_populate_response(response, 0, NULL, 204); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - - } - /* - nf_server_populate_response(response, 0, NULL, 204); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - - if(methods) ogs_free(methods); - */ - } else { - char *err = NULL; - int number_of_components; - const nf_server_interface_metadata_t *interface; - if (message.h.resource.component[2]){ - if (!strcmp(message.h.resource.component[2],"certificates")) { - number_of_components = 2; - if (message.h.resource.component[3]) { - number_of_components = 3; - } - interface = m1_servercertificatesprovisioning_api; - } else if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { - number_of_components = 2; - interface = m1_contenthostingprovisioning_api; - - } - } else if (message.h.resource.component[0]){ - if (!strcmp(message.h.resource.component[0],"provisioning-sessions")){ - number_of_components = 0; - if (message.h.resource.component[1]) { - number_of_components = 1; - } - interface = m1_provisioningsession_api; - - } - } - asprintf(&err,"Method [%s]: [%s] - Provisioning Session [%s] does not exist.", message.h.method, message.h.resource.component[2], message.h.resource.component[1]); - ogs_error("Method [%s]: [%s] - Provisioning Session [%s] does not exist.", message.h.method, message.h.resource.component[2], message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, 404, number_of_components, &message, "Provisioning Session does not exists.", err, NULL, interface, app_meta)); - - } - - } else { - methods = ogs_msprintf("%s, %s",OGS_SBI_HTTP_METHOD_POST, OGS_SBI_HTTP_METHOD_OPTIONS); - response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_provisioningsession_api, app_meta); - nf_server_populate_response(response, 0, NULL, 204); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - - } - if(methods) ogs_free(methods); - } else { - char *err = NULL; - asprintf(&err,"Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[0]); - ogs_error("Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[0]); - ogs_assert(true == nf_server_send_error(stream, 404, 0, &message, "Target not yet supported.", err, NULL, m1_provisioningsession_api, app_meta)); - - } - break; - - DEFAULT - ogs_error("Invalid HTTP method [%s]", message.h.method); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 0, &message, "Invalid HTTP method.", message.h.method, NULL, NULL, app_meta)); - - END - break; - - DEFAULT - char *err; - ogs_error("Invalid resource name [%s]", - message.h.resource.component[0]); - asprintf(&err,"Invalid resource name [%s]", message.h.resource.component[0]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid resource name", err, NULL, NULL, app_meta)); - - END -======= ->>>>>>> Stashed changes ogs_sbi_message_free(&message); break; From 983fd6ed11c8fe6c7c0b3dde97b610bf1d2cdfe3 Mon Sep 17 00:00:00 2001 From: deva Date: Wed, 15 Mar 2023 17:58:22 +0000 Subject: [PATCH 25/48] includes previous bug fixes and code improvements --- src/5gmsaf/msaf-m1-sm.c | 60 ++++++++++++++++++++++++++++++--------- src/5gmsaf/msaf-m5-sm.c | 4 +-- src/5gmsaf/msaf-mgmt-sm.c | 4 +-- 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/5gmsaf/msaf-m1-sm.c b/src/5gmsaf/msaf-m1-sm.c index 543af7b..9e4b430 100644 --- a/src/5gmsaf/msaf-m1-sm.c +++ b/src/5gmsaf/msaf-m1-sm.c @@ -361,7 +361,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_free(location); msaf_certificate_free(csr_cert); - return; + break; } if (ogs_list_first(&msaf_provisioning_session->msaf_application_servers) == NULL) { @@ -435,17 +435,49 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *provisioning_session_type, *external_app_id, *asp_id = NULL; msaf_provisioning_session_t *msaf_provisioning_session; - cJSON_ArrayForEach(entry, prov_sess) { - if(!strcmp(entry->string, "provisioningSessionType")){ - provisioning_session_type = entry->valuestring; - } - if(!strcmp(entry->string, "aspId")){ - asp_id = entry->valuestring; - } - if(!strcmp(entry->string, "externalApplicationId")){ - external_app_id = entry->valuestring; + ogs_debug("createProvisioningSession: received=\"%s\"", request->http.content); + + entry = cJSON_GetObjectItemCaseSensitive(prov_sess, "provisioningSessionType"); + if (!entry) { + const char *err = "createProvisioningSession: \"provisioningSessionType\" is not present"; + ogs_error(err); + ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); + break; + } + if (!cJSON_IsString(entry)) { + const char *err = "createProvisioningSession: \"provisioningSessionType\" is not a string"; + ogs_error(err); + ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); + break; + } + provisioning_session_type = entry->valuestring; + + entry = cJSON_GetObjectItemCaseSensitive(prov_sess, "externalApplicationId"); + if (!entry) { + const char *err = "createProvisioningSession: \"externalApplicationId\" is not present"; + ogs_error(err); + ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); + break; + } + if (!cJSON_IsString(entry)) { + const char *err = "createProvisioningSession: \"externalApplicationId\" is not a string"; + ogs_error(err); + ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); + break; + } + external_app_id = entry->valuestring; + + entry = cJSON_GetObjectItemCaseSensitive(prov_sess, "aspId"); + if (entry) { + if (!cJSON_IsString(entry)) { + const char *err = "createProvisioningSession: \"aspId\" is not a string"; + ogs_error(err); + ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); + break; } + asp_id = entry->valuestring; } + msaf_provisioning_session = msaf_provisioning_session_create(provisioning_session_type, asp_id, external_app_id); provisioning_session = msaf_provisioning_session_get_json(msaf_provisioning_session->provisioningSessionId); if (provisioning_session != NULL) { @@ -1711,7 +1743,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) break; END break; - +#if 0 CASE(OGS_SBI_SERVICE_NAME_NNRF_NFM) SWITCH(message.h.resource.component[0]) @@ -1761,7 +1793,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_assert_if_reached(); END break; - +#endif DEFAULT ogs_error("Invalid service name [%s]", message.h.service.name); ogs_assert_if_reached(); @@ -1770,7 +1802,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_sbi_message_free(&message); ogs_sbi_response_free(response); break; - +#if 0 case OGS_EVENT_SBI_TIMER: ogs_assert(e); @@ -1822,7 +1854,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_timer_get_name(e->h.timer_id), e->h.timer_id); } break; - +#endif default: ogs_error("No handler for event %s", msaf_event_get_name(e)); break; diff --git a/src/5gmsaf/msaf-m5-sm.c b/src/5gmsaf/msaf-m5-sm.c index bedfdc1..52b5141 100644 --- a/src/5gmsaf/msaf-m5-sm.c +++ b/src/5gmsaf/msaf-m5-sm.c @@ -158,7 +158,7 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e) END break; - +#if 0 case OGS_EVENT_SBI_CLIENT: ogs_assert(e); @@ -296,7 +296,7 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_timer_get_name(e->h.timer_id), e->h.timer_id); } break; - +#endif default: ogs_error("No handler for event %s", msaf_event_get_name(e)); break; diff --git a/src/5gmsaf/msaf-mgmt-sm.c b/src/5gmsaf/msaf-mgmt-sm.c index 335e2b5..89180cf 100644 --- a/src/5gmsaf/msaf-mgmt-sm.c +++ b/src/5gmsaf/msaf-mgmt-sm.c @@ -88,7 +88,7 @@ void msaf_maf_mgmt_state_functional(ogs_fsm_t *s, msaf_event_t *e) END break; - +#if 0 case OGS_EVENT_SBI_CLIENT: ogs_assert(e); @@ -227,7 +227,7 @@ void msaf_maf_mgmt_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_timer_get_name(e->h.timer_id), e->h.timer_id); } break; - +#endif default: ogs_error("No handler for event %s", msaf_event_get_name(e)); break; From 1a3adcfaa4b5d04e649af5a905487acd37c35acb Mon Sep 17 00:00:00 2001 From: David Waring Date: Wed, 15 Mar 2023 17:22:06 +0000 Subject: [PATCH 26/48] Implement some missing operations for m1-session-cli --- .../python3/lib/rt_m1_client/certificates.py | 178 +++++++ tools/python3/lib/rt_m1_client/session.py | 121 ++++- tools/python3/lib/rt_m1_client/types.py | 11 +- tools/python3/m1_session_cli.py | 438 ++++++++++++++++-- 4 files changed, 701 insertions(+), 47 deletions(-) create mode 100644 tools/python3/lib/rt_m1_client/certificates.py diff --git a/tools/python3/lib/rt_m1_client/certificates.py b/tools/python3/lib/rt_m1_client/certificates.py new file mode 100644 index 0000000..f0b49a1 --- /dev/null +++ b/tools/python3/lib/rt_m1_client/certificates.py @@ -0,0 +1,178 @@ +#!/usr/bin/python3 +#============================================================================== +# 5G-MAG Reference Tools: M1 Client Certificate Signing +#============================================================================== +# +# File: rt_m1_client/certificates.py +# License: 5G-MAG Public License (v1.0) +# Author: David Waring +# Copyright: (C) 2023 British Broadcasting Corporation +# +# For full license terms please see the LICENSE file distributed with this +# program. If this file is missing then the license can be retrieved from +# https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view +# +#============================================================================== +# +# M1 Session Certificate Signing +# ============================= +# +# This module defines classes used by the M1 session classes to sign certificates +# +# CertificateSigner - Base class for certificate signing. +# +# LocalCACertificateSigner - A CertificateSigner that uses a locally generated CA to generate X509 certificates from CSRs +# +# DefaultCertificateSigner - The default CertificateSigner used by the M1Session class, presently LocalCACertificateSigner. +# +''' +====================================================== +5G-MAG Reference Tools: M1 Session Certificate Signing +====================================================== + +This module defines some classes that can be used by the `M1Session` class to provide certificate signing services. + +''' +from typing import Optional + +import OpenSSL + +from .data_store import DataStore + +class CertificateSigner: + '''Base class for all CertificateSigner classes + ''' + def __init__(self, *args, data_store: Optional[DataStore] = None, **kwargs): + self.data_store = data_store + + def __await__(self): + '''Await method + + This allows the class to be instantiated with asynchronous initialisation, e.g.:: + cert_signer = await MyCertificateSigner() + + This will call the async method `asyncInit` to perform the asynchronous initialisation operations. + ''' + return self.asyncInit().__await__() + + async def asyncInit(self): + '''Asynchronous object initialisation + + Derived classes should override this if they have object initialisation to do that requires async operations. + + This async method must return self. + ''' + return self + + async def signCertificate(self, csr: str, *args, domain_name_alias: Optional[str] = None, **kwargs) -> str: + '''Sign a CSR in PEM format and return the public X509 Certificate in PEM format + + :param str csr: A CSR in PEM format. + :param str domain_name_alias: Optional domain name to add to the subjectAltNames in the final certificate. + + :return: a public X509 certificate in PEM format. + ''' + raise NotImplementedError('Class derived from CertificateSigner must implement this method') + +class LocalCACertificateSigner(CertificateSigner): + '''CertificateSigner that uses a locally generated CA kept in the data store + ''' + + def __init__(self, *args, data_store: Optional[DataStore] = None, local_ca_days: int = 365, temp_ca_days: int = 1, local_cert_days: int = 30, **kwargs): + super().__init__(self, data_store=data_store) + self.__ca_key = None + self.__ca = None + self.__local_ca_days = local_ca_days + self.__temp_ca_days = temp_ca_days + self.__local_cert_days = local_cert_days + + async def signCertificate(self, csr: str, *args, domain_name_alias: Optional[str] = None, **kwargs) -> str: + '''Sign a CSR in PEM format and return the public X509 Certificate in PEM format + + :param str csr: A CSR in PEM format. + :param str domain_name_alias: Optional domain name to add to the subjectAltNames in the final certificate. + + :return: a public X509 certificate in PEM format. + ''' + x509req: OpenSSL.crypto.X509Req = OpenSSL.crypto.load_certificate_request(OpenSSL.crypto.FILETYPE_PEM, csr.encode('utf-8')) + need_canonical_sans = True + for ext in x509req.get_extensions(): + ext_name = ext.get_short_name().decode('utf-8') + if ext_name == 'subjectAltName' and str(ext) == 'DNS:'+x509req.get_subject().commonName: + need_canonical_sans = False + sans: List[OpenSSL.crypto.X509Extension] = [] + if need_canonical_sans: + sans += [OpenSSL.crypto.X509Extension(b'subjectAltName', False, b'DNS:'+x509req.get_subject().commonName)] + if domain_name_alias is not None: + sans += [OpenSSL.crypto.X509Extension(b'subjectAltName', False, b'DNS:'+domain_name_alias.encode('utf-8'))] + x509req.add_extensions(sans) + # Get local CA + ca_key, ca = await self.__getLocalCA() + # Convert CSR to X509 certificate + x509 = OpenSSL.crypto.X509() + x509.set_subject(x509req.get_subject()) + x509.set_serial_number(1) + x509.gmtime_adj_notBefore(0) + x509.gmtime_adj_notAfter(self.__local_cert_days * 24 * 60 * 60) + x509.set_issuer(ca.get_subject()) + x509.set_pubkey(x509req.get_pubkey()) + for ext in x509req.get_extensions(): + if ext.get_short_name() != b'authorityKeyIdentifier' and ext.get_short_name() != b'basicConstraints': + x509.add_extensions([ext]) + x509.add_extensions([ + OpenSSL.crypto.X509Extension(b'authorityKeyIdentifier', False, b'keyid, issuer', issuer=ca), + OpenSSL.crypto.X509Extension(b'basicConstraints', True, b'CA:FALSE') + ]) + x509.sign(ca_key, "sha256") + return OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, x509).decode('utf-8') + + async def __makeCACert(self, key: OpenSSL.crypto.PKey, cn: str, days: int = 365): + ca = OpenSSL.crypto.X509() + ca_name = ca.get_subject() + # TODO: Get these values from configured values + ca_name.organizationName = '5G-MAG' + ca_name.commonName = cn + ca.set_issuer(ca_name) + # TODO: increment serial number from data-store + ca.set_serial_number(1) + ca.gmtime_adj_notBefore(0) + ca.gmtime_adj_notAfter(days*24*60*60) + ca.set_pubkey(key) + ca.add_extensions([ + OpenSSL.crypto.X509Extension(b'basicConstraints', True, b'CA:TRUE,pathlen:1'), + OpenSSL.crypto.X509Extension(b'subjectKeyIdentifier', False, b'hash', subject=ca), + OpenSSL.crypto.X509Extension(b'authorityKeyIdentifier', False, b'keyid, issuer:always', issuer=ca), + ]) + ca.sign(key, 'sha256') + return ca + + async def __getLocalCA(self): + if self.__ca_key is None or self.__ca is None: + if self.data_store: + ca_key_pem = await self.data_store.get('ca-private') + if ca_key_pem is not None: + self.__ca_key = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, ca_key_pem) + else: + self.__ca_key = OpenSSL.crypto.PKey() + self.__ca_key.generate_key(OpenSSL.crypto.TYPE_RSA, 4096) + await self.data_store.set('ca-private', OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, self.__ca_key).decode('utf-8')) + ca_pem = await self.data_store.get('ca-public') + if ca_pem is not None: + self.__ca = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, ca_pem) + else: + self.__ca = await self.__makeCACert(self.__ca_key, '5G-MAG Reference Tools Local CA', days=self.__local_ca_days) + await self.data_store.set('ca-public', OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, self.__ca).decode('utf-8')) + else: + self.__ca_key = OpenSSL.crypto.PKey() + self.__ca_key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048) + self.__ca = await self.__makeCACert(self.__ca_key, 'Temporary Demo CA', days=self.__temp_ca_days) + + return self.__ca_key, self.__ca + +DefaultCertificateSigner = LocalCACertificateSigner + +__all__ = [ + "M1Error", + "M1ClientError", + "M1ServerError", + ] diff --git a/tools/python3/lib/rt_m1_client/session.py b/tools/python3/lib/rt_m1_client/session.py index 0a34923..d050ca1 100644 --- a/tools/python3/lib/rt_m1_client/session.py +++ b/tools/python3/lib/rt_m1_client/session.py @@ -34,15 +34,19 @@ Function via the interface at reference point M1. ''' import datetime +import importlib import logging from typing import Optional, Union, Tuple, Dict, Any, TypedDict, List +import OpenSSL + from .exceptions import (M1ClientError, M1ServerError, M1Error) from .types import (ApplicationId, ContentHostingConfiguration, ContentProtocols, ProvisioningSessionType, ProvisioningSession, ResourceId, PROVISIONING_SESSION_TYPE_DOWNLINK) from .client import (M1Client, ProvisioningSessionResponse, ContentHostingConfigurationResponse, ServerCertificateResponse, ServerCertificateSigningRequestResponse, ContentProtocolsResponse) from .data_store import DataStore +from .certificates import CertificateSigner, DefaultCertificateSigner class M1Session: '''M1 Session management class @@ -51,11 +55,14 @@ class M1Session: This class is used as the top level class to manage a communication session with the 5GMS Application Function. ''' - def __init__(self, host_address: Tuple[str,int], persistent_data_store: Optional[DataStore] = None): + def __init__(self, host_address: Tuple[str,int], persistent_data_store: Optional[DataStore] = None, certificate_signer: Optional[Union[CertificateSigner,type,str]] = None): self.__m1_host = host_address self.__data_store_dir = persistent_data_store + self.__cert_signer = certificate_signer self.__m1_client = None self.__provisioning_sessions = {} + self.__ca_key = None + self.__ca = None self.__log = logging.getLogger(__name__ + '.' + self.__class__.__name__) def __await__(self): @@ -152,11 +159,34 @@ async def certificateCreate(self, provisioning_session_id: ResourceId) -> Option ps = await self.__getProvisioningSessionCache(provisioning_session_id) if ps is not None: if 'certificates' not in ps or ps['certificates'] is None: - ps['certificates'] = [cert_id] - elif cert_id not in ps['certificates']: - ps['certificates'] += [cert_id] + # create certificates cache + ps['certificates'] = {cert_id: {k.lower(): v for k,v in cert_resp.items()}} + elif cert_id not in ps['certificates'] or ps['certificates'][cert_id] is None: + # Store new certificate info + ps['certificates'][cert_id] = {k.lower(): v for k,v in cert_resp.items()} + else: + # Update the certificate info + if cert_resp['ServerCertificate'] is None: + cert_resp['ServerCertificate'] = ps['certificates'][cert_id]['servercertificate'] + ps['certificates'][cert_id] = {k.lower(): v for k,v in cert_resp.items()} + return cert_id + async def certificateGet(self, provisioning_session_id: ResourceId, certificate_id: ResourceId) -> Optional[str]: + ret_err = None + if provisioning_session_id not in self.__provisioning_sessions: + return None + try: + await self.__cacheCertificates(provisioning_session_id) + except M1Error as err: + ret_err = err + ps = self.__provisioning_sessions[provisioning_session_id] + if 'certificates' not in ps or ps['certificates'] is None or certificate_id not in ps['certificates']: + return None + if ret_err is not None and ps['certificates'][certificate_id]['servercertificate'] is None: + raise ret_err + return ps['certificates'][certificate_id]['servercertificate'] + async def certificateNewSigningRequest(self, provisioning_session_id: ResourceId) -> Optional[Tuple[ResourceId,str]]: if provisioning_session_id not in self.__provisioning_sessions: return None @@ -174,6 +204,12 @@ async def certificateNewSigningRequest(self, provisioning_session_id: ResourceId ps['certificates'] += [cert_id] return (cert_id,cert_resp['CertificateSigningRequestPEM']) + async def certificateSet(self, provisioning_session_id: ResourceId, certificate_id: ResourceId, pem: str) -> Optional[bool]: + if provisioning_session_id not in self.__provisioning_sessions: + return None + await self.__connect() + return await self.__m1_client.uploadServerCertificate(provisioning_session_id, certificate_id, pem) + # ContentHostingConfiguration methods async def contentHostingConfigurationCreate(self, provisioning_session: ResourceId, chc: ContentHostingConfiguration) -> bool: @@ -194,20 +230,41 @@ async def contentHostingConfigurationGet(self, provisioning_session: ResourceId) return None await self.__cacheContentHostingConfiguration(provisioning_session) ps = await self.__getProvisioningSessionCache(provisioning_session) - if ps is None: + if ps is None or ps['content-hosting-configuration'] is None: return None return ContentHostingConfiguration(ps['content-hosting-configuration']['contenthostingconfiguration']) # Convenience methods - async def createNewDownlinkPullStream(self, ingesturl, entrypoint, app_id, name=None, asp_id=None, ssl=False, insecure=True): + async def createDownlinkPullProvisioningSession(self, app_id, asp_id=None) -> Optional[ResourceId]: + return await self.provisioningSessionCreate(PROVISIONING_SESSION_TYPE_DOWNLINK, app_id, asp_id) + + async def createNewCertificate(self, provisioning_session: ResourceId, domain_name_alias: Optional[str] = None) -> Optional[ResourceId]: + # simple case just create the certificate + if domain_name_alias is None or len(domain_name_alias) == 0: + return await self.certificateCreate(provisioning_session) + # When domainNameAlias is used we need to use a CSR + csr: Optional[Tuple[ResourceId,str]] = await self.certificateNewSigningRequest(provisioning_session) + if csr is None: + return None + cert_id = csr[0] + csr_pem = csr[1] + cert_signer = await self.__getCertificateSigner() + cert: str = await cert_signer.signCertificate(csr_pem, domain_name_alias=domain_name_alias) + # Send new cert to the AF + if not await self.certificateSet(provisioning_session, cert_id, cert): + self.__log.error('Failed to upload certificate with domainNameAlias') + return None + return cert_id + + async def createNewDownlinkPullStream(self, ingesturl, entrypoint, app_id, name=None, asp_id=None, ssl=False, insecure=True, domain_name_alias=None): # Create a new provisioning session provisioning_session: ResourceId = await self.provisioningSessionCreate(PROVISIONING_SESSION_TYPE_DOWNLINK, app_id, asp_id) if provisioning_session is None: raise RuntimeError('Failed to create a provisioning session') # Create an SSL certificate if requested if ssl: - cert: Optional[ResourceId] = await self.certificateCreate(provisioning_session) + cert: Optional[ResourceId] = await self.createNewCertificate(provisioning_session, domain_name_alias=domain_name_alias) if cert is None: if insecure: self.__log.warn('Failed to create hosting with HTTPS, continuing with just HTTP') @@ -227,9 +284,15 @@ async def createNewDownlinkPullStream(self, ingesturl, entrypoint, app_id, name= 'distributionConfigurations': [] } if ssl and cert is not None: - chc['distributionConfigurations'] += [{'certificateId': cert}] + dc = {'certificateId': cert} + if domain_name_alias is not None: + dc['domainNameAlias'] = domain_name_alias + chc['distributionConfigurations'] += [dc] if insecure: - chc['distributionConfigurations'] += [{}] + dc = {} + if domain_name_alias is not None: + dc['domainNameAlias'] = domain_name_alias + chc['distributionConfigurations'] += [dc] if entrypoint is not None: chc['entryPointPath'] = entrypoint if not await self.contentHostingConfigurationCreate(provisioning_session, chc): @@ -289,7 +352,10 @@ async def __cacheProvisioningSession(self, prov_sess: ResourceId): ps.update({ 'protocols': None, 'content-hosting-configuration': None, + 'certificates': None, }) + if 'serverCertificateIds' in ps['provisioningsession']: + ps['certificates'] = {k: None for k in ps['provisioningsession']['serverCertificateIds']} async def __cacheProtocols(self, provisioning_session_id: ResourceId): await self.__cacheProvisioningSession(provisioning_session_id) @@ -301,6 +367,30 @@ async def __cacheProtocols(self, provisioning_session_id: ResourceId): if result is not None: ps['protocols'].update({k.lower(): v for k,v in result.items()}) + async def __cacheCertificates(self, provisioning_session_id: ResourceId): + await self.__cacheProvisioningSession(provisioning_session_id) + ps = self.__provisioning_sessions[provisioning_session_id] + now = datetime.datetime.now(datetime.timezone.utc) + if ps['certificates'] is None: + return + ret_err = None + for cert_id,cert in list(ps['certificates'].items()): + if cert is None: + cert = {'etag': None, 'last-modified': None, 'cache-until': None, 'servercertificateid': cert_id, + 'servercertificate': None} + ps['certificates'][cert_id] = cert + if cert['cache-until'] is None or cert['cache-until'] < now: + await self.__connect() + try: + result = await self.__m1_client.retrieveServerCertificate(provisioning_session_id, cert_id) + if result is not None: + cert.update({k.lower(): v for k,v in result.items()}) + except M1Error as err: + if ret_err is None: + ret_err = err + if ret_err is not None: + raise ret_err + async def __cacheContentHostingConfiguration(self, provisioning_session_id: ResourceId): await self.__cacheProvisioningSession(provisioning_session_id) ps = self.__provisioning_sessions[provisioning_session_id] @@ -317,6 +407,19 @@ async def __cacheContentHostingConfiguration(self, provisioning_session_id: Reso else: ps['content-hosting-configuration'] = None + async def __getCertificateSigner(self): + if self.__cert_signer is None: + self.__cert_signer = 'rt_m1_client.certificates.DefaultCertificateSigner' + if isinstance(self.__cert_signer, str): + cert_sign_cls_mod, cert_sign_cls_name = self.__cert_signer.rsplit('.', 1) + cert_sign_cls_mod = importlib.import_module(cert_sign_cls_mod) + self.__cert_signer = getattr(cert_sign_cls_mod, cert_sign_cls_name) + if issubclass(self.__cert_signer, CertificateSigner): + self.__cert_signer = await self.__cert_signer(data_store=self.__data_store_dir) + if not isinstance(self.__cert_signer, CertificateSigner): + raise RuntimeError('The certificate signer class given is not derived from CertificateSigner') + return self.__cert_signer + async def __connect(self): if self.__m1_client is None: self.__m1_client = M1Client(self.__m1_host) diff --git a/tools/python3/lib/rt_m1_client/types.py b/tools/python3/lib/rt_m1_client/types.py index 1495ebf..6faf4ac 100644 --- a/tools/python3/lib/rt_m1_client/types.py +++ b/tools/python3/lib/rt_m1_client/types.py @@ -197,7 +197,7 @@ def fromJSON(chc_json: str) -> "ContentHostingConfiguration": @classmethod def format(cls, chc: "ContentHostingConfiguration") -> str: return f'''Name: {chc['name']} -Ingest: +{cls.__formatEntryPoint(chc)}Ingest: Type: {chc['ingestConfiguration']['protocol']} URL: {chc['ingestConfiguration']['baseURL']} Distributions: @@ -212,9 +212,18 @@ def __formatDistributions(cls, chc: "ContentHostingConfiguration", indent: int = s = f"{prefix}- URL: {d['baseURL']}" if 'certificateId' in d: s += f"\n{prefix} Certificate: {d['certificateId']}" + if 'domainNameAlias' in d: + s += f"\n{prefix} Domain Name Alias: {d['domainNameAlias']}" dists += [s] return '\n'.join(dists) + @classmethod + def __formatEntryPoint(cls, chc: "ContentHostingConfiguration", indent: int = 0) -> str: + if 'entryPointPath' not in chc: + return '' + prefix = ' '*indent + return f"{prefix}Entry Point Path: {chc['entryPointPath']}\n" + # TS 29.571 ProblemDetail class InvalidParamMandatory(TypedDict): ''' diff --git a/tools/python3/m1_session_cli.py b/tools/python3/m1_session_cli.py index a691112..e919d42 100755 --- a/tools/python3/m1_session_cli.py +++ b/tools/python3/m1_session_cli.py @@ -20,28 +20,68 @@ # This is a command line tool to perform operations on the 5GMS Application # Function via the M1 interface. # -'''5G-MAG Reference Tools: M1 Session CLI +''' +====================================== +5G-MAG Reference Tools: M1 Session CLI +====================================== Perform operations on the 5GMS Application Function via the interface at reference point M1. Syntax: m1-session-cli -h + m1-session-cli configure -h m1-session-cli configure show m1-session-cli configure set m1-session-cli configure get + m1-session-cli list -h m1-session-cli list [-v] - m1-session-cli new-stream [--with-ssl|--ssl-only] [] + m1-session-cli new-provisioning-session -h + m1-session-cli new-provisioning-session [-e ] [-a ] + m1-session-cli new-stream [-e ] [-a ] [-n ] [--with-ssl|--ssl-only] + [] + m1-session-cli del-stream -h m1-session-cli del-stream -p m1-session-cli del-stream [] - m1-session-cli check-certificate-renewal - m1-session-cli renew-certificate -p - m1-session-cli renew-certificate [] + m1-session-cli set-stream -h + m1-session-cli set-stream -p + m1-session-cli new-certificate -h + m1-session-cli new-certificate -p [-d | --csr] + m1-session-cli show-certificate -h + m1-session-cli show-certificate -p -c + m1-session-cli set-certificate -h + m1-session-cli set-certificate -p -c [] + m1-session-cli check-certificates-renewal -h + m1-session-cli check-certificates-renewal + m1-session-cli renew-certificates -h + m1-session-cli renew-certificates -p + m1-session-cli renew-certificates [] + +Parameters: + -a ID --asp-id ID The application service provider id. + -c ID --certificate-id ID The certificate id to operate on. + -d FQDN --domain-name-alias FQDN The alternate domain name to use. + -e ID --external-app-id ID The external application id. + -h --help Display the help message. + -n NAME --name NAME The hosting name. + -p ID --provisioning-session-id ID The provisioning session id to use. + --ssl-only Provide HTTPS only. + --with-ssl Provide both HTTPS and HTTP. + +Arguments: + certificate-PEM-file The file path of a PEM holding a public certificate. + ContentHostingConfiguration-JSON The file path of a JSON file holding a ContentHostingConfiguration. + entry-point-suffix-URL Optional media entry URL path. + ingest-URL The base URL to fetch content from. + key The configuration field name. + value The configuration field value. ''' +import aiofiles import argparse import asyncio import configparser +import datetime from io import StringIO import logging import os @@ -49,13 +89,18 @@ import sys from typing import Tuple, List +import json +import OpenSSL + from rt_m1_client.session import M1Session from rt_m1_client.exceptions import M1Error from rt_m1_client.data_store import JSONFileDataStore from rt_m1_client.types import ContentHostingConfiguration class Configuration: - '''App configuration + '''Application configuration container + + This class handles the loading and saving of the application configuration ''' DEFAULT_CONFIG='''[DEFAULT] @@ -70,9 +115,15 @@ class Configuration: m1_port = 7777 asp_id = external_app_id = please-change-this - ''' + certificate_signing_class = rt_m1_client.certificates.DefaultCertificateSigner + ''' #: The default configuration def __init__(self): + '''Constructor + + Will load the previous configuration from ``/etc/rt-5gms/m1-client.conf`` if the command is run by root or + ``~/.rt-5gms/m1-client.conf`` if run by any other user. + ''' self.__config_filename = None if os.getuid() != 0: self.__config_filename = os.path.expanduser(os.path.join('~', '.rt-5gms', 'm1-client.conf')) @@ -86,14 +137,35 @@ def __init__(self): self.__config.read(self.__config_filename) def isKey(self, key: str) -> str: + '''Does a configuration field key exist? + + This tests *key* for being a valid configuration option field key name. + + :returns: The key string if it is a valid configuration field key. + :raises: ValueError if the key string does not match a known configuration field key. + ''' if key in self.__default_config['m1-client']: return key raise ValueError('Not a valid configuration option') def get(self, key: str, default: str = None, raw: bool = False) -> str: + '''Get a configuration value + + Retrieves the value for configuration option *key*. If the *key* does not exist the *default* will be returned. If *raw* is + ``True`` and the *key* option exists then the raw configuration (without ``%()`` interpolation) value will be returned. + + :returns: The configuration option *key* value or *default* if key does not exist. + ''' return self.__config.get('m1-client', key, raw=raw, fallback=default) def set(self, key: str, value: str) -> bool: + '''Set a configuration value + + Sets the raw *value* for configuration option *key*. If *key* is not a valid configuration option then ValueError exception + will be raised. + + The configuration is saved once the *key* option has been set. + ''' self.isKey(key) if key in self.__default_config['DEFAULT']: section = 'DEFAULT' @@ -104,17 +176,35 @@ def set(self, key: str, value: str) -> bool: return True def isDefault(self, key: str) -> bool: + '''Checks if a key contains the default configuration value + + :returns: ``True`` if the configuration value for *key* is the default value, or ``False`` otherwise. + ''' return self.__config.get('m1-client', key) == self.__default_config.get('m1-client', key) def getKeys(self) -> List[str]: + '''Get a list of configuration field name keys + + :returns: A list of configuration key names. + ''' return list(self.__default_config['m1-client'].keys()) def resetValue(self, key: str) -> bool: + '''Reset a configuration field to its default value + + :returns: ``True`` if the field was reset or ``False`` if the field already contained the default value. + ''' if self.isDefault(key): return False return self.set(key, self.__default_config.get('m1-client', key)) def __saveConfig(self): + '''Save the current configuration to local storage + + :meta private-method: + + Will save the current configuration to the relevant local file. Fields with the default value will be saved as a comment. + ''' cfgdir = os.path.dirname(self.__config_filename) if not os.path.exists(cfgdir): os.makedirs(cfgdir, mode=0o755) @@ -130,66 +220,208 @@ def __saveConfig(self): cfgout.write(f'{key} = {cfgvalue}\n') cfgout.write('\n') - def __str__(self): + '''String representation of the configuration + + :returns: A ``str`` representing the configuration. + ''' buf = StringIO() self.__config.write(buf) return buf.getvalue() def __repr__(self): + '''Textual represnetation of the Configuration object + + :returns: A ``str`` representation of the Configuration object. + ''' return f'Configuration(config="{self}")' async def cmd_configure_show(args: argparse.Namespace, config: Configuration) -> int: + '''Perform ``configure show`` operation + + Will write to stdout the current configuration. + ''' default_marker = {True: ' (default)', False: ''} print('Configuration settings:') print('\n'.join([f'{key} = {config.get(key, raw=True)}{default_marker[config.isDefault(key)]}' for key in config.getKeys()])) return 0 async def cmd_configure_reset(args: argparse.Namespace, config: Configuration) -> int: + '''Perform ``configure reset`` operation + + Will reset the configuration option *key* back to its default value. + ''' config.resetValue(args.key) return 0 async def cmd_configure_get(args: argparse.Namespace, config: Configuration) -> int: + '''Perform ``configure get`` operation + + Write to stdout an interpolated configuration option in the form ``=""``. This could be evaluated in an external + shell. + ''' print(f'{args.key}={repr(config.get(args.key))}') return 0 async def cmd_configure_set(args: argparse.Namespace, config: Configuration) -> int: + '''Perform ``configure set`` operation + + Set a configuration value and save the new configuration. + ''' config.set(args.key, args.value) return 0 +def __formatX509Name(x509name: OpenSSL.crypto.X509Name) -> str: + '''Format an X509Name as a comma separated DN string + + :meta private: + :param OpenSSL.crypto.X509Name x509name: The X509 name to convert to a string. + :return: a ``str`` version of the X509 Name as comma separated DN fields. + :rtype: str + ''' + ret = ",".join([f"{name.decode('utf-8')}={value.decode('utf-8')}" for name,value in x509name.get_components()]) + return ret + +async def __prettyPrintCertificate(cert: str, indent: int = 0) -> None: + '''Print certificate information from X509 PEM data + + :param str cert: X509 certificate encoded as PEM data + :param int indent: The indent to use in the certificate output + ''' + x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert) + serial = x509.get_serial_number() + subject = x509.get_subject() + issuer = x509.get_issuer() + start_str = x509.get_notBefore() + if isinstance(start_str, bytes): + start_str = start_str.decode('utf-8') + start = datetime.datetime.strptime(start_str, '%Y%m%d%H%M%SZ').replace(tzinfo=datetime.timezone.utc) + end_str = x509.get_notAfter() + if isinstance(end_str, bytes): + end_str = end_str.decode('utf-8') + end = datetime.datetime.strptime(end_str, '%Y%m%d%H%M%SZ').replace(tzinfo=datetime.timezone.utc) + subject_key = None + issuer_key = None + for ext_num in range(x509.get_extension_count()): + ext = x509.get_extension(ext_num) + ext_name = ext.get_short_name().decode('utf-8') + if ext_name == "subjectKeyIdentifier": + subject_key = str(ext) + elif ext_name == "authorityKeyIdentifier": + issuer_key = str(ext) + cert_info_prefix=' '*indent + cert_desc=f'{cert_info_prefix}Serial = {serial}\n{cert_info_prefix}Not before = {start}\n{cert_info_prefix}Not after = {end}\n{cert_info_prefix}Subject = {__formatX509Name(subject)}\n' + if subject_key is not None: + cert_desc += f'{cert_info_prefix} key={subject_key}\n' + cert_desc += f'{cert_info_prefix}Issuer = {__formatX509Name(issuer)}' + if issuer_key is not None: + cert_desc += f'\n{cert_info_prefix} key={issuer_key}' + print(f'{cert_desc}') + async def cmd_list_verbose(args: argparse.Namespace, config: Configuration) -> int: + '''Perform ``list -v`` operation + + Output to stdout a verbose list of the defined provisioning sessions and their resources. + ''' session = await get_session(config) for ps_id in await session.provisioningSessionIds(): print(f'{ps_id}:') certs = await session.certificateIds(ps_id) print(' Certificates:') - print('\n'.join([' '+cert for cert in certs])) + for cert_id in certs: + print(f' {cert_id}:') + try: + cert = await session.certificateGet(ps_id, cert_id) + if cert is not None: + await __prettyPrintCertificate(cert, indent=6) + else: + print(' Certificate not yet uploaded') + except M1Error as err: + print(f' Certificate not available: {str(err)}') chc = await session.contentHostingConfigurationGet(ps_id) print(' ContentHostingConfiguration:') - print('\n'.join([' '+line for line in ContentHostingConfiguration.format(chc).split('\n')])) + if chc is not None: + print('\n'.join([' '+line for line in ContentHostingConfiguration.format(chc).split('\n')])) + else: + print(' Not defined') return 0 async def cmd_list(args: argparse.Namespace, config: Configuration) -> int: + '''Perform ``list`` operation + + Output to stdout a list of the defined provisioning session ids, one per line. + ''' if args.verbose: return await cmd_list_verbose(args, config) session = await get_session(config) print('\n'.join(await session.provisioningSessionIds())) return 0 +async def cmd_new_provisioning_session(args: argparse.Namespace, config: Configuration) -> int: + '''Perform ``new-provisioning-session`` operation + + This will reserve a new, empty, provisioning session. + + Will output to stdout the result including the new provisioning session id. + ''' + session = await get_session(config) + app_id = args.app_id or config.get('external_app_id') + asp_id = args.asp_id or config.get('asp_id') + provisioning_session_id: Optional[ResourceId] = await session.createDownlinkPullProvisioningSession(app_id, asp_id=asp_id) + if provisioning_session_id is None: + print(f'Failed to create a new provisioing session') + return 1 + print(f'Provisioning session {provisioning_session_id} created') + return 0 + +async def cmd_set_stream(args: argparse.Namespace, config: Configuration) -> int: + '''Perform ``set-stream`` operation + + This will set the ContentHostingConfiguration for a provisioning session. + + Will output to stdout the result. + ''' + session = await get_session(config) + provisioning_session_id = args.provisioning_session + + async with aiofiles.open(args.file, 'r') as json_in: + chc = json.loads(await json_in.read()) + result = await session.contentHostingConfigurationCreate(provisioning_session_id, chc) + if not result: + print(f'Failed to set hosting for provisioning session {provisioning_session_id}') + return 1 + print(f'Hosting set for provisioning session {provisioning_session_id}') + return 0 + async def cmd_new_stream(args: argparse.Namespace, config: Configuration) -> int: + '''Perform ``new-stream`` operation + + This will generate and set the ContentHostingConfiguration for a provisioning session. If asked to provide an SSL distribution + point it will also generate the ServerCertificate within the provisioning session. + + Will output to stdout the result. + ''' session = await get_session(config) name = args.name use_ssl = args.with_ssl or args.ssl_only use_plain = not args.ssl_only app_id = args.app_id or config.get('external_app_id') asp_id = args.asp_id or config.get('asp_id') - provisioning_session_id = await session.createNewDownlinkPullStream(args.ingesturl, args.entrypoint, name=name, ssl=use_ssl, insecure=use_plain, app_id=app_id, asp_id=asp_id) + domain_name_alias = args.domain_name_alias + provisioning_session_id = await session.createNewDownlinkPullStream(args.ingesturl, args.entrypoint, name=name, ssl=use_ssl, insecure=use_plain, app_id=app_id, asp_id=asp_id, domain_name_alias=domain_name_alias) print(f'Hosting created as provisioning session {provisioning_session_id}') return 0 async def cmd_delete_stream(args: argparse.Namespace, config: Configuration) -> int: - if args.provisioning_session_id is not None: - ps_id = args.provisioning_session_id + '''Perform ``delete-stream`` operation + + This will delete the provisioning session. + + This will remove the provisioning session and all its resources. + ''' + session = await get_session(config) + if args.provisioning_session is not None: + ps_id = args.provisioning_session else: ps_id = await session.provisioningSessionIdByIngestUrl(args.ingesturl, args.entrypointsuffix) if ps_id is None: @@ -198,7 +430,71 @@ async def cmd_delete_stream(args: argparse.Namespace, config: Configuration) -> await session.provisioningSessionDestroy(ps_id) return 0 +async def cmd_new_certificate(args: argparse.Namespace, config: Configuration) -> int: + ''' Perform ``new-certificate`` operation + + This will create or reserve a new certificate in the provisioning session. + ''' + session = await get_session(config) + if args.csr: + result = await session.certificateNewSigningRequest(args.provisioning_session) + if result is None: + print('Failed to reserve certificate') + return 1 + cert_id, csr = result + print(f'certificate_id={cert_id}') + print(csr) + return 0 + cert_id = await session.createNewCertificate(args.provisioning_session, domain_name_alias=args.domain_name_alias) + if cert_id is None: + print('Failed to create certificate') + return 1 + print(f'certificate_id={cert_id}') + return 0 + +async def cmd_show_certificate(args: argparse.Namespace, config: Configuration) -> int: + ''' Perform ``show-certificate`` operation + + Display the certificate details for a given certificate. + ''' + session = await get_session(config) + result = await session.certificateGet(args.provisioning_session, args.certificate_id) + if result is None: + print(f'Unable to get certificate {args.certificate_id} for provisioning session {args.provisioning_session}') + return 1 + await __prettyPrintCertificate(result) + return 0 + +async def cmd_set_certificate(args: argparse.Namespace, config: Configuration) -> int: + ''' Perform ``set-certificate`` operation + + Set the public certificate for a ``new-certificate`` generated with the ``--csr`` flag. + ''' + session = await get_session(config) + if args.certificate_pem_file is None: + loop = asyncio.get_event_loop() + reader = asyncio.StreamReader() + protocol = asyncio.StreamReaderProtocol(reader) + await loop.connect_read_pipe(lambda: protocol, sys.stdin) + else: + reader = aiofiles.open(args.certificate_pem_file, 'r') + cert_pem = await reader.read() + await reader.close() + result = await session.certificateSet(args.provisioning_session, args.certificate_id, cert_pem) + if result is None: + print('Failed to set certificate') + return 1 + if not result: + print('Certificate already set') + return 1 + print('Certificate set') + return 0 + async def cmd_check_all_renewal(args: argparse.Namespace, config: Configuration) -> int: + '''Perform ``check-all-renewal`` operation + + **TODO** + ''' session = await get_session(config) for ps_id in await session.provisioningSessionIds(): chc = await session.getContentHostingConfiguration(ps_id) @@ -212,8 +508,12 @@ async def cmd_check_all_renewal(args: argparse.Namespace, config: Configuration) return 1 async def cmd_renew_certs(args: argparse.Namespace, config: Configuration) -> int: + '''Perform ``renew-certs`` operation + + **TODO** + ''' session = await get_session(config) - ps_id = args.provisioning_session_id + ps_id = args.provisioning_session chc = await session.getContentHostingConfiguration(ps_id) # get list of unique cert ids in chc # for each cert id in list @@ -224,30 +524,43 @@ async def cmd_renew_certs(args: argparse.Namespace, config: Configuration) -> in return 1 async def parse_args() -> Tuple[argparse.Namespace,Configuration]: + '''Parse command line options and load app configuration + + :return: Tuple containing the command line arguments after validation and the app configuration + :rtype: Tuple[argparse.Namespace,Configuration] + ''' cfg = Configuration() parser = argparse.ArgumentParser(prog='m1-session-cli', description='M1 Session Tool') subparsers = parser.add_subparsers(required=True) + # m1-session-cli configure ... parser_configure = subparsers.add_parser('configure', help='Local configuration') configure_subparsers = parser_configure.add_subparsers(required=True) + # m1-session-cli configure show parser_configure_show = configure_subparsers.add_parser('show', help='Show local configuration') parser_configure_show.set_defaults(command=cmd_configure_show) + # m1-session-cli configure get parser_configure_get = configure_subparsers.add_parser('get', help='Get local configuration value') parser_configure_get.set_defaults(command=cmd_configure_get) parser_configure_get.add_argument('key', metavar='KEY', type=cfg.isKey) + # m1-session-cli configure set parser_configure_set = configure_subparsers.add_parser('set', help='Set local configuration value') parser_configure_set.set_defaults(command=cmd_configure_set) parser_configure_set.add_argument('key', metavar='KEY', type=cfg.isKey) parser_configure_set.add_argument('value', metavar='VALUE') + # m1-session-cli configure reset parser_configure_reset = configure_subparsers.add_parser('reset', help='Reset configuration value to its default') parser_configure_reset.set_defaults(command=cmd_configure_reset) parser_configure_reset.add_argument('key', metavar='KEY', type=cfg.isKey) + # m1-session-cli list [-v] parser_list = subparsers.add_parser('list', help='List provisioning sessions') parser_list.set_defaults(command=cmd_list) parser_list.add_argument('-v', '--verbose', required=False, action='store_true') + # m1-session-cli new-stream [-e ] [-a ] [-n ] [--with-ssl|--ssl-only] [-d ] \ + # [] parser_newstream = subparsers.add_parser('new-stream', help='Create a new ingest stream') parser_newstream.set_defaults(command=cmd_new_stream) parser_newstream.add_argument('-n', '--name', metavar='NAME', help='The name of the new stream', required=False) @@ -256,42 +569,92 @@ async def parse_args() -> Tuple[argparse.Namespace,Configuration]: parser_newstream_ssl_options = parser_newstream.add_mutually_exclusive_group(required=False) parser_newstream_ssl_options.add_argument('--with-ssl', action='store_true') parser_newstream_ssl_options.add_argument('--ssl-only', action='store_true') + parser_newstream.add_argument('-d', '--domain-name-alias', dest='domain_name_alias', metavar='FQDN', help='Optional domain name alias for the distribution', required=False) parser_newstream.add_argument('ingesturl', metavar='ingest-URL', help='The ingest URL prefix to use') - parser_newstream.add_argument('entrypoint', metavar='entry-point-URL', nargs='?', - help='The media player entry point suffix.') + parser_newstream.add_argument('entrypoint', metavar='entry-point-path', nargs='?', + help='The media player entry point path suffix.') + # m1-session-cli del-stream -p + # m1-session-cli del-stream [] parser_delstream = subparsers.add_parser('del-stream', help='Delete an ingest stream') parser_delstream.set_defaults(command=cmd_delete_stream) parser_delstream_filter = parser_delstream.add_mutually_exclusive_group(required=True) parser_delstream_filter.add_argument('-p', '--provisioning-session', help='Delete by provisioning session id') - #parser_delstream_filter_byurl = parser_delstream_filter.add_argument_group() - #parser_delstream_filter_byurl.add_argument('ingesturl', metavar='ingest-URL', nargs=1, - # help='The ingest URL prefix to use') - #parser_delstream_filter_byurl.add_argument('entrypoint', metavar='entry-point-URL', nargs='?', - # help='The media player entry point suffix.') parser_delstream_filter.add_argument('ingesturl', metavar='ingest-URL', nargs='?', help='The ingest URL prefix to use') - + # The entry-point-path should go with ingest-URL, but argparser lacks the ability to do subgroups + parser_delstream.add_argument('entrypoint', metavar='entry-point-path', nargs='?', help='The media player entry point suffix.') + + # m1-session-cli set-stream -p + parser_set_stream = subparsers.add_parser('set-stream', help='Set the hosting for a provisioning session from a JSON file') + parser_set_stream.set_defaults(command=cmd_set_stream) + parser_set_stream.add_argument('-p', '--provisioning-session', help='The provisioning session id to set the hosting for', required=True) + parser_set_stream.add_argument('file', metavar='CHC-JSON-FILE', help='A filepath to a JSON encoded ContentHostingConfiguration') + + # m1-session-cli new-provisioning-session [-e ] [-a ] + parser_new_provisioning_session = subparsers.add_parser('new-provisioning-session', help='Create a new provisioning session') + parser_new_provisioning_session.set_defaults(command=cmd_new_provisioning_session) + parser_new_provisioning_session.add_argument('-e', '--external-app-id', dest='app_id', metavar="APPLICATION-ID", help='The external application id to register the stream to', required=False) + parser_new_provisioning_session.add_argument('-a','--asp-id', metavar="PROVIDER-ID", help="The Application Service Provider Id to use", required=False) + + # m1-session-cli new-certificate -p [-d | --csr] + parser_new_certificate = subparsers.add_parser('new-certificate', help='Create a new certificate') + parser_new_certificate.set_defaults(command=cmd_new_certificate) + parser_new_certificate.add_argument('-p', '--provisioning-session', + help='Provisioning session id to create the new certificate for') + parser_new_certificate_extras = parser_new_certificate.add_mutually_exclusive_group(required=False) + parser_new_certificate_extras.add_argument('-d', '--domain-name-alias', dest='domain_name_alias', + help='FQDN to add as an extra domain name to the certificate') + parser_new_certificate_extras.add_argument('--csr', action='store_true', + help='Return a CSR to be signed externally and returned using set-certificate') + + # m1-session-cli show-certificate -p -c + parser_show_certificate = subparsers.add_parser('show-certificate', help='Retrieve a public certificate') + parser_show_certificate.set_defaults(command=cmd_show_certificate) + parser_show_certificate.add_argument('-p', '--provisioning-session', required=True, + help='Provisioning session id to show the certificate for') + parser_show_certificate.add_argument('-c', '--certificate-id', required=True, + help='The certificate id of the certificate to show') + + # m1-session-cli set-certificate -p -c [] + parser_set_certificate = subparsers.add_parser('set-certificate', + help='Set the public certificate for a certificate created using --csr') + parser_set_certificate.set_defaults(command=cmd_set_certificate) + parser_set_certificate.add_argument('-p', '--provisioning-session', required=True, + help='Provisioning session id to set the certificate for') + parser_set_certificate.add_argument('-c', '--certificate-id', required=True, + help='The certificate id of the certificate to set') + parser_set_certificate.add_argument('certificate-PEM-file', nargs='?', + help='PEM file to load the public certificate from, if omitted will use stdin instead') + + # m1-session-cli check-certificate-renewal parser_checkrenewal = subparsers.add_parser('check-certificate-renewal', help='Renew all certificates if close to expiry') parser_checkrenewal.set_defaults(command=cmd_check_all_renewal) + # m1-session-cli renew-certificate -p + # m1-session-cli renew-certificate [] parser_renewcert = subparsers.add_parser('renew-certificate', help='Force renewal of a specific certificate') parser_renewcert.set_defaults(command=cmd_renew_certs) parser_renewcert_filter = parser_renewcert.add_mutually_exclusive_group(required=True) parser_renewcert_filter.add_argument('-p', '--provisioning-session', help='Renew by provisioning session id') - #parser_renewcert_filter_byurl = parser_renewcert_filter.add_argument_group(required=False) - #parser_renewcert_filter_byurl.add_argument('ingesturl', metavar='ingest-URL', nargs=1, - # help='The ingest URL prefix to use') - #parser_renewcert_filter_byurl.add_argument('entrypoint', metavar='entry-point-URL', nargs='?', - # help='The media player entry point suffix.') parser_renewcert_filter.add_argument('ingesturl', metavar='ingest-URL', nargs='?', help='The ingest URL prefix to use') + # The entry-point-path should go with ingest-URL, but argparser lacks the ability to do subgroups + parser_renewcert.add_argument('entrypoint', metavar='entry-point-path', nargs='?', help='The media player entry point suffix.') args = parser.parse_args() return (args,cfg) -_m1_session = None +_m1_session = None #: singleton variable for the M1Session object async def get_session(config: Configuration) -> M1Session: + '''Get the current M1Session object + + If the M1Session object does not exist, create it. + + :param Configuration config: The application configuration to use for connection information. + :return: the M1Session instance. + :rtype: M1Session + ''' global _m1_session if _m1_session is None: data_store_dir = config.get('data_store') @@ -299,27 +662,28 @@ async def get_session(config: Configuration) -> M1Session: data_store = await JSONFileDataStore(config.get('data_store')) else: data_store = None - _m1_session = await M1Session((config.get('m1_address', 'localhost'), config.get('m1_port',7777)), data_store) + _m1_session = await M1Session((config.get('m1_address', 'localhost'), config.get('m1_port',7777)), data_store, config.get('certificate_signing_class')) return _m1_session async def main(): ''' Async application entry point ''' + log_levels = { + 'debug': logging.DEBUG, + 'info': logging.INFO, + 'warn': logging.WARN, + 'error': logging.ERROR, + 'crit': logging.CRITICAL, + } try: (args, config) = await parse_args() - logging.basicConfig(level={k.lower(): v for k,v in logging.getLevelNamesMapping().items()}[config.get('log_level')]) + logging.basicConfig(level=log_levels[config.get('log_level')]) log = logging.getLogger() if hasattr(args, 'command'): return await args.command(args, config) else: print(repr(parse_args())) - return 0 - - provisioning_session_id = await m1_session.createNewDownlinkPullStream('https://ftp.itec.aau.at/datasets/DASHDataset2014/BigBuckBunny/4sec/', 'BigBuckBunny_4s_onDemand_2014_05_09.mpd', name='Test CHC', ssl=True, insecure=False, app_id='myAppId', asp_id='myAspId') - print(f'Created Provisioning Session: {provisioning_session_id}') - prov_sess = m1_session.getProvisioningSession(provisioning_session_id) - print(f'ProvisioningSession = {repr(prov_sess)}') except M1Error as err: print(f'Communication error: {err}') return 2 @@ -327,7 +691,7 @@ async def main(): def app(): ''' - Application entry point + Sync application entry point ''' logging.basicConfig(level=logging.INFO) return asyncio.run(main()) From e74d9aadaa86a86ac050d91c120aa4c448c15c52 Mon Sep 17 00:00:00 2001 From: David Waring Date: Wed, 15 Mar 2023 17:22:27 +0000 Subject: [PATCH 27/48] Install m1-session-cli --- tools/meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/meson.build b/tools/meson.build index 459abd9..6a7e0d9 100644 --- a/tools/meson.build +++ b/tools/meson.build @@ -4,7 +4,8 @@ fs = import('fs') support_scripts_dir = get_option('libexecdir') / 'rt-5gms' scripts = { -'python3/m1_client_cli.py': 'm1-client' +'python3/m1_client_cli.py': 'm1-client', +'python3/m1_session_cli.py': 'm1-session' } support_scripts = { From 32d98f5d73eee1a3ddeeea5bda33147eae77f7d5 Mon Sep 17 00:00:00 2001 From: David Waring Date: Thu, 16 Mar 2023 10:14:46 +0000 Subject: [PATCH 28/48] Fix bugs and compiler warnings. - Fix memory leaks on errors - Efficiency improvements to error reporting. - Fix compiler warning about unused variables, use uninitialised and incorrect format type. --- src/5gmsaf/context.c | 51 ++++---- src/5gmsaf/msaf-m1-sm.c | 197 ++++++++++++------------------ src/5gmsaf/msaf-m5-sm.c | 29 ++--- src/5gmsaf/msaf-mgmt-sm.c | 11 +- src/5gmsaf/provisioning-session.c | 2 +- 5 files changed, 112 insertions(+), 178 deletions(-) diff --git a/src/5gmsaf/context.c b/src/5gmsaf/context.c index d31a00a..f805ff1 100644 --- a/src/5gmsaf/context.c +++ b/src/5gmsaf/context.c @@ -438,7 +438,7 @@ int msaf_context_parse_config(void) } } if(!matches) { - ogs_sbi_server_t *server = ogs_sbi_server_add( + server = ogs_sbi_server_add( node6->addr, is_option ? &option : NULL); ogs_assert(server); @@ -448,38 +448,37 @@ int msaf_context_parse_config(void) if (key) server->tls.key = key; if (pem) server->tls.pem = pem; - } - if (!strcmp(msaf_key, "sbi")) { - ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.sbi_server_sockaddr_v6, server->node.addr)); - if(!self->config.m1_server_sockaddr_v6){ + if (!strcmp(msaf_key, "sbi")) { + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.sbi_server_sockaddr_v6, server->node.addr)); + if(!self->config.m1_server_sockaddr_v6){ + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.m1_server_sockaddr_v6, server->node.addr)); + } + if(!self->config.m5_server_sockaddr_v6){ + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.m5_server_sockaddr_v6, server->node.addr)); + } + if(!self->config.maf_mgmt_server_sockaddr_v6){ + ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.maf_mgmt_server_sockaddr_v6, server->node.addr)); + } + } + if (!strcmp(msaf_key, "m1")) { + if(self->config.m1_server_sockaddr_v6){ + ogs_freeaddrinfo(self->config.m1_server_sockaddr_v6); + } ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.m1_server_sockaddr_v6, server->node.addr)); } - if(!self->config.m5_server_sockaddr_v6){ + if (!strcmp(msaf_key, "m5")) { + if(self->config.m5_server_sockaddr_v6){ + ogs_freeaddrinfo(self->config.m5_server_sockaddr_v6); + } ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.m5_server_sockaddr_v6, server->node.addr)); } - if(!self->config.maf_mgmt_server_sockaddr_v6){ + if (!strcmp(msaf_key, "maf")) { + if(self->config.maf_mgmt_server_sockaddr_v6){ + ogs_freeaddrinfo(self->config.maf_mgmt_server_sockaddr_v6); + } ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.maf_mgmt_server_sockaddr_v6, server->node.addr)); } } - if (!strcmp(msaf_key, "m1")) { - if(self->config.m1_server_sockaddr_v6){ - ogs_freeaddrinfo(self->config.m1_server_sockaddr_v6); - } - ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.m1_server_sockaddr_v6, server->node.addr)); - } - if (!strcmp(msaf_key, "m5")) { - if(self->config.m5_server_sockaddr_v6){ - ogs_freeaddrinfo(self->config.m5_server_sockaddr_v6); - } - ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.m5_server_sockaddr_v6, server->node.addr)); - } - if (!strcmp(msaf_key, "maf")) { - if(self->config.maf_mgmt_server_sockaddr_v6){ - ogs_freeaddrinfo(self->config.maf_mgmt_server_sockaddr_v6); - } - ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.maf_mgmt_server_sockaddr_v6, server->node.addr)); - } - } if (addr) diff --git a/src/5gmsaf/msaf-m1-sm.c b/src/5gmsaf/msaf-m1-sm.c index 9e4b430..5c225cb 100644 --- a/src/5gmsaf/msaf-m1-sm.c +++ b/src/5gmsaf/msaf-m1-sm.c @@ -84,12 +84,8 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_sbi_stream_t *stream = NULL; ogs_sbi_request_t *request = NULL; - - ogs_sbi_nf_instance_t *nf_instance = NULL; - ogs_sbi_subscription_data_t *subscription_data = NULL; ogs_sbi_response_t *response = NULL; ogs_sbi_message_t message; - ogs_sbi_xact_t *sbi_xact = NULL; msaf_sm_debug(e); @@ -125,14 +121,11 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) CASE("3gpp-m1") if (strcmp(message.h.api.version, "v2") != 0) { char *error; - ogs_error("Not supported version [%s]", message.h.api.version); - error = ogs_msprintf("Version [%s] not supported", message.h.api.version); - + ogs_error("%s", error); ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL, app_meta)); ogs_sbi_message_free(&message); - ogs_free(error); break; } SWITCH(message.h.resource.component[0]) @@ -151,10 +144,10 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/x-www-form-urlencoded")) { char *err = NULL; - char *type = NULL; - type = (char *)ogs_hash_this_val(hi); - ogs_error("Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); + const char *type; + type = (const char *)ogs_hash_this_val(hi); asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); ogs_sbi_message_free(&message); @@ -194,16 +187,16 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_list_add(&as_state->purge_content_hosting_cache, purge_cache); } else { - ogs_error("Provisioning Session [%s] is not assigned to an Application Server", message.h.resource.component[1]); char *err = NULL; asprintf(&err,"Provisioning Session [%s] is not assigned to an Application Server", message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session is not assigned to an Application Server.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } } } else { - ogs_error("Provisioning Session [%s]: Unable to get information about Application Server", message.h.resource.component[1]); char *err = NULL; asprintf(&err,"Provisioning Session [%s] : Unable to get information about Application Server", message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Unable to get information about Application Server", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } @@ -219,12 +212,10 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_assert(true == ogs_sbi_server_send_response(stream, response)); } } else { - ogs_error("Unable to retrieve the Provisioning Session [%s]", message.h.resource.component[1]); char *err = NULL; asprintf(&err,"Provisioning session [%s] does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - } } @@ -248,10 +239,8 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) if(!uri_relative_check(entry->valuestring)) { char *err = NULL; asprintf(&err,"While creating the Content Hosting Configuration for the Provisioning Session [%s], entryPointPath does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring ); - ogs_error("While creating the Content Hosting Configuration for the Provisioning Session [%s], entryPointPath does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring); - + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - cJSON_Delete(content_hosting_config); break; } @@ -288,32 +277,28 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) cJSON_Delete(content_hosting_config); } else { char *err = NULL; - ogs_error("Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); asprintf(&err,"Unable to retrieve the Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } } else { char *err = NULL; - ogs_error("Verification error on Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); asprintf(&err,"Verification error on Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 400, 2, &message, "Bad Content Hosting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } } else { char *err = NULL; - - ogs_error("Failed to populate Content Hosting Configuration for the Provisioning Session [%s].", message.h.resource.component[1]); asprintf(&err,"Creation of the Content Hosting Configuration failed for the Provisioning Session [%s]", message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 500, 2, &message, "Creation of the Content Hosting Configuration failed.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } } else { char *err = NULL; asprintf(&err,"Provisioning session [%s]does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); - + ogs_error("%s",err); ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - - } } @@ -406,8 +391,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { char *err = NULL; asprintf(&err,"Provisioning session [%s] does not exists.", message.h.resource.component[1]); - ogs_error("Provisioning session [%s] does not exists.", message.h.resource.component[1]); - + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } } @@ -416,15 +400,15 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) msaf_provisioning_session_t *msaf_provisioning_session; msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); if(msaf_provisioning_session) { - ogs_error("Method [%s] not allowed for [%s]", message.h.method, message.h.resource.component[1]); char *err = NULL; asprintf(&err,"Method [%s] not allowed for [%s].", message.h.method, message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 405, 1, &message, "Method not allowed.", err, NULL, m1_provisioningsession_api, app_meta)); } else { char *err = NULL; asprintf(&err,"Provisioning session [%s] does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Provisioning session does not exist.", err, NULL, m1_provisioningsession_api, app_meta)); } @@ -441,13 +425,13 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) if (!entry) { const char *err = "createProvisioningSession: \"provisioningSessionType\" is not present"; ogs_error(err); - ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); + ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", ogs_strdup(err), NULL, m1_provisioningsession_api, app_meta)); break; } if (!cJSON_IsString(entry)) { const char *err = "createProvisioningSession: \"provisioningSessionType\" is not a string"; ogs_error(err); - ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); + ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", ogs_strdup(err), NULL, m1_provisioningsession_api, app_meta)); break; } provisioning_session_type = entry->valuestring; @@ -456,13 +440,13 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) if (!entry) { const char *err = "createProvisioningSession: \"externalApplicationId\" is not present"; ogs_error(err); - ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); + ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", ogs_strdup(err), NULL, m1_provisioningsession_api, app_meta)); break; } if (!cJSON_IsString(entry)) { const char *err = "createProvisioningSession: \"externalApplicationId\" is not a string"; ogs_error(err); - ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); + ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", ogs_strdup(err), NULL, m1_provisioningsession_api, app_meta)); break; } external_app_id = entry->valuestring; @@ -472,7 +456,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) if (!cJSON_IsString(entry)) { const char *err = "createProvisioningSession: \"aspId\" is not a string"; ogs_error(err); - ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); + ogs_assert(true == nf_server_send_error(stream, 400, 1, &message, "Creation of the Provisioning session failed.", ogs_strdup(err), NULL, m1_provisioningsession_api, app_meta)); break; } asp_id = entry->valuestring; @@ -499,10 +483,9 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) cJSON_Delete(provisioning_session); cJSON_Delete(prov_sess); } else { - char *err = NULL; - asprintf(&err,"Creation of the Provisioning session failed."); - ogs_error("Creation of the Provisioning session failed."); - ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Creation of the Provisioning session failed.", err, NULL, m1_provisioningsession_api, app_meta)); + const char *err = "Creation of the Provisioning session failed."; + ogs_error(err); + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Creation of the Provisioning session failed.", ogs_strdup(err), NULL, m1_provisioningsession_api, app_meta)); } } @@ -520,11 +503,11 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) provisioning_session_cert = ogs_hash_get(msaf_provisioning_session->certificate_map, message.h.resource.component[3], OGS_HASH_KEY_STRING); cert = server_cert_retrieve(message.h.resource.component[3]); if(!cert || !provisioning_session_cert) { - ogs_error("Certificate [%s] management problem", message.h.resource.component[3]); char *err = NULL; asprintf(&err,"Certificate [%s] management problem", message.h.resource.component[3]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - return; + break; } if(!cert->return_code) { @@ -541,7 +524,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else if(cert->return_code == 4){ char *err = NULL; asprintf(&err,"Certificate [%s] does not exists.", cert->id); - ogs_error("Certificate [%s] does not exists.", cert->id); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } else if(cert->return_code == 8){ @@ -553,7 +536,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { char *err = NULL; asprintf(&err,"Certificate [%s] management problem.", cert->id); - ogs_error("Certificate [%s] management problem.", cert->id); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } msaf_certificate_free(cert); @@ -561,7 +544,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { char *err = NULL; asprintf(&err,"Provisioning session [%s] is not available.", message.h.resource.component[1]); - ogs_error("Provisioning session [%s] is not available.", message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } } @@ -585,19 +568,17 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) cJSON_Delete(chc); } else { char *err = NULL; - ogs_error("Provisioning Session [%s]: Unable to retrieve the Content Hosting Configuration", message.h.resource.component[1]); asprintf(&err,"Provisioning Session [%s]: Unable to retrieve the Content Hosting Configuration", message.h.resource.component[1]); - + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Unable to retrieve the Content Hosting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } } else { char *err = NULL; asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - } } else if (!strcmp(message.h.resource.component[2],"protocols")) { @@ -611,7 +592,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { char *err = NULL; asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contentprotocolsdiscovery_api, app_meta)); } } @@ -638,7 +619,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { char *err = NULL; asprintf(&err,"Provisioning Session [%s] is not available.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] is not available.", message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exists.", err, NULL, m1_provisioningsession_api, app_meta)); } @@ -667,10 +648,9 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) if(!uri_relative_check(entry->valuestring)) { char *err = NULL; asprintf(&err,"While updating the Content Hosting Configuration for the Provisioning Session [%s], Entry Point Path does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring ); - ogs_error("While updating the Content Hosting Configuration for the provisioning Session [%s], Entry Point Path does not match the regular expression [%s].",message.h.resource.component[1], entry->valuestring); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Entry Point Path does not match the regular expression.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - cJSON_Delete(content_hosting_config); break; } @@ -704,12 +684,9 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { char *err = NULL; - ogs_error("Provisioning Session [%s]: Failed to update the Content Hosting Configuration.", message.h.resource.component[1]); asprintf(&err,"Provisioning Session [%s]: Update to Content Hosting Configuration failed.", message.h.resource.component[1]); - ogs_error("Update of the Content Hosting Configuration failed."); - + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Failed to update the contentHostingConfiguration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); - } } if (message.h.resource.component[1] && !strcmp(message.h.resource.component[2],"certificates") && message.h.resource.component[3]) { @@ -726,10 +703,10 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/x-pem-file")) { char *err = NULL; - char *type = NULL; - type = (char *)ogs_hash_this_val(hi); - ogs_error("Unsupported Media Type: received type: %s, should have been application/x-pem-file", type); + const char *type; + type = ogs_hash_this_val(hi); asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-pem-file", type); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 415, 3, &message, "Unsupported Media Type.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); ogs_sbi_message_free(&message); @@ -758,34 +735,32 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else if (rv == 3 && provisioning_session_cert ) { char *err = NULL; - ogs_error("A server certificate with id [%s] already exist", cert_id); asprintf(&err,"A server certificate with id [%s] already exist", cert_id); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 403, 3, &message, "A server certificate already exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } else if(rv == 4 || ! provisioning_session_cert) { char *err = NULL; - ogs_error("Server certificate with id [%s] does not exist", cert_id); asprintf(&err,"Server certificate with id [%s] does not exist", cert_id); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Server certificate does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } else if(rv == 5) { char *err = NULL; - ogs_error("CSR was never generated for this certificate Id [%s]", cert_id); asprintf(&err,"CSR was never generated for this certificate Id [%s]", cert_id); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "CSR was never generated for the certificate.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } else if(rv == 6) { char *err = NULL; - ogs_error("The public certificate [%s] provided does not match the key", cert_id); asprintf(&err,"The public certificate [%s] provided does not match the key", cert_id); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 400, 3, &message, "The public certificate provided does not match the key.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } else { char *err = NULL; - ogs_error("There was a certificate management problem for the certificate id [%s]", cert_id); asprintf(&err,"There was a certificate management problem for the certificate id [%s].", cert_id); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "There was a certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - - } ogs_free(cert); } @@ -795,16 +770,15 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { char *err = NULL; asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - } } else { char *err = NULL; asprintf(&err,"[%s]: Resource not found.", message.h.method); - ogs_error("[%s]: Resource not found.", message.h.method); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Resource not found.", err, NULL, m1_provisioningsession_api, app_meta)); } break; @@ -828,14 +802,14 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else if (rv == 4 ) { char *err = NULL; asprintf(&err,"Certificate [%s] does not exist.", message.h.resource.component[3]); - ogs_error("Certificate [%s] does not exist.", message.h.resource.component[3]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } else { char *err = NULL; asprintf(&err,"Certificate management problem for certificate [%s].", message.h.resource.component[3]); - ogs_error("Certificate management problem."); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } @@ -843,11 +817,9 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { char *err = NULL; asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); - ogs_error("Provisioning session [%s] does not exist.", message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - - } } else if (message.h.resource.component[1] && message.h.resource.component[2]) { msaf_provisioning_session_t *msaf_provisioning_session; @@ -867,13 +839,13 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { char *err = NULL; asprintf(&err,"Provisioning Session [%s] has no Content Hosting Configuration.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] has no Content Hosting Configuration.", message.h.resource.component[1] ); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Content Hosting Configuration does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } } else { char *err = NULL; asprintf(&err,"Provisioning Session [%s] does not exists.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] does not exists.", message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } @@ -887,10 +859,9 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) char *err = NULL; asprintf(&err,"Provisioning session [%s] either not found or already marked for deletion.", message.h.resource.component[1]); - ogs_error("Provisioning session [%s] either not found or already marked for deletion.",message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Provisioning session either not found or already marked for deletion.", err, NULL, m1_provisioningsession_api, app_meta)); - } else { provisioning_session->marked_for_deletion = 1; response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_provisioningsession_api, app_meta); @@ -930,11 +901,11 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_assert(true == ogs_sbi_server_send_response(stream, response)); msaf_certificate_free(cert); } else { - ogs_error("Certificate [%s] management problem", message.h.resource.component[3]); char *err = NULL; asprintf(&err,"Certificate [%s] management problem", message.h.resource.component[3]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 500, 3, &message, "Certificate management problem.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); - return; + break; } } else { methods = ogs_msprintf("%s",OGS_SBI_HTTP_METHOD_POST); @@ -954,7 +925,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { char *err = NULL; asprintf(&err,"Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[2]); - ogs_error("Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[2]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Target not yet supported.", err, NULL, NULL, app_meta)); } } else { @@ -999,9 +970,8 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } } asprintf(&err,"Method [%s]: [%s] - Provisioning Session [%s] does not exist.", message.h.method, message.h.resource.component[2], message.h.resource.component[1]); - ogs_error("Method [%s]: [%s] - Provisioning Session [%s] does not exist.", message.h.method, message.h.resource.component[2], message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, number_of_components, &message, "Provisioning Session does not exists.", err, NULL, interface, app_meta)); - } } else { @@ -1016,26 +986,22 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { char *err = NULL; asprintf(&err,"Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[0]); - ogs_error("Method [%s]: Target [%s] not yet supported.", message.h.method, message.h.resource.component[0]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 0, &message, "Target not yet supported.", err, NULL, m1_provisioningsession_api, app_meta)); - } break; DEFAULT ogs_error("Invalid HTTP method [%s]", message.h.method); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 0, &message, "Invalid HTTP method.", message.h.method, NULL, NULL, app_meta)); - + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 0, &message, "Invalid HTTP method.", ogs_strdup(message.h.method), NULL, NULL, app_meta)); END break; DEFAULT - char *err; - ogs_error("Invalid resource name [%s]", - message.h.resource.component[0]); + char *err = NULL; asprintf(&err,"Invalid resource name [%s]", message.h.resource.component[0]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid resource name", err, NULL, NULL, app_meta)); - END ogs_sbi_message_free(&message); break; @@ -1043,14 +1009,11 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) CASE("5gmag-rt-management") if (strcmp(message.h.api.version, "v1") != 0) { char *error; - ogs_error("Not supported version [%s]", message.h.api.version); - error = ogs_msprintf("Version [%s] not supported", message.h.api.version); - + ogs_error("%s", error); ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, maf_management_api, app_meta)); ogs_sbi_message_free(&message); - ogs_free(error); break; } SWITCH(message.h.resource.component[0]) @@ -1071,28 +1034,25 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) break; } else { ogs_error("Internal Server Error."); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR, 0, &message, "Internal Server Error.", message.h.method, NULL, maf_management_api, app_meta)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR, 0, &message, "Internal Server Error.", ogs_strdup(message.h.method), NULL, maf_management_api, app_meta)); } DEFAULT ogs_error("Invalid HTTP method [%s]", message.h.method); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 0, &message, "Invalid HTTP method.", message.h.method, NULL, maf_management_api, app_meta)); - + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 0, &message, "Invalid HTTP method.", ogs_strdup(message.h.method), NULL, maf_management_api, app_meta)); END break; DEFAULT - char *err; - ogs_error("Invalid resource name [%s]", message.h.resource.component[0]); - asprintf(&err,"Invalid resource name [%s]", message.h.resource.component[0]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid resource name", err, NULL, NULL, app_meta)); - + char *err = NULL; + asprintf(&err,"Invalid resource name [%s]", message.h.resource.component[0]); + ogs_error("%s", err); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Invalid resource name", err, NULL, NULL, app_meta)); END ogs_sbi_message_free(&message); - break; - + break; DEFAULT ogs_error("Invalid API name [%s]", message.h.service.name); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid API name.", message.h.service.name, NULL, NULL, app_meta)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid API name.", ogs_strdup(message.h.service.name), NULL, NULL, app_meta)); END break; @@ -1154,10 +1114,10 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/json")) { char *err = NULL; - char *type = NULL; - type = (char *)ogs_hash_this_val(hi); - ogs_error("Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); + const char *type; + type = ogs_hash_this_val(hi); asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 415, 2, &message, "Provisioning session does not exist.", err, NULL, m3_contenthostingprovisioning_api, app_meta)); ogs_sbi_message_free(&message); @@ -1282,7 +1242,6 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } } - ogs_free(error); cJSON_Delete(purge_cache_err); } @@ -1440,7 +1399,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) break; DEFAULT ogs_error("Unknown M3 Content Hosting Configuration operation [%s]", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Content Hosting Configuration operation", message.h.resource.component[1], NULL, NULL, app_meta)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Content Hosting Configuration operation", ogs_strdup(message.h.resource.component[1]), NULL, NULL, app_meta)); break; END break; @@ -1493,11 +1452,10 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) next_action_for_application_server(as_state); break; DEFAULT - char *err; - ogs_error("Unknown M3 Content Hosting Configuration operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + char *err = NULL; asprintf(&err, "Unknown M3 Content Hosting Configuration operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Content Hosting Configuration operation", err, NULL, NULL, app_meta)); - break; END break; @@ -1668,7 +1626,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) break; DEFAULT ogs_error("Unknown M3 certificate operation [%s]", message.h.resource.component[1]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 certificate operation.", message.h.resource.component[1], NULL, NULL, app_meta)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 certificate operation.", ogs_strdup(message.h.resource.component[1]), NULL, NULL, app_meta)); break; END break; @@ -1724,11 +1682,10 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) next_action_for_application_server(as_state); break; DEFAULT - char *err; - ogs_error("Unknown M3 certificate operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + char *err = NULL; asprintf(&err, "Unsupported M3 Certificate operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Certificate operation", err, NULL, NULL, app_meta)); - break; END break; @@ -1739,7 +1696,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) DEFAULT ogs_error("Unknown M3 operation [%s]", message.h.resource.component[0]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unsupported M3 operation", message.h.resource.component[0], NULL, NULL, app_meta)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unsupported M3 operation", ogs_strdup(message.h.resource.component[0]), NULL, NULL, app_meta)); break; END break; diff --git a/src/5gmsaf/msaf-m5-sm.c b/src/5gmsaf/msaf-m5-sm.c index 52b5141..eed271b 100644 --- a/src/5gmsaf/msaf-m5-sm.c +++ b/src/5gmsaf/msaf-m5-sm.c @@ -43,16 +43,9 @@ void msaf_m5_state_final(ogs_fsm_t *s, msaf_event_t *e) void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e) { - int rv; - ogs_sbi_stream_t *stream = NULL; ogs_sbi_request_t *request = NULL; - - ogs_sbi_nf_instance_t *nf_instance = NULL; - ogs_sbi_subscription_data_t *subscription_data = NULL; - ogs_sbi_response_t *response = NULL; ogs_sbi_message_t message; - ogs_sbi_xact_t *sbi_xact = NULL; msaf_sm_debug(e); @@ -83,15 +76,11 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e) CASE("3gpp-m5") if (strcmp(message.h.api.version, "v2") != 0) { char *error; - ogs_error("Not supported version [%s]", message.h.api.version); - error = ogs_msprintf("Version [%s] not supported", message.h.api.version); - + ogs_error("%s", error); ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, NULL, "Not supported version", error, NULL, NULL, app_meta)); ogs_sbi_message_free(&message); - ogs_free(error); - break; } SWITCH(message.h.resource.component[0]) @@ -105,9 +94,8 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e) if(msaf_provisioning_session == NULL) { char *err = NULL; asprintf(&err,"Provisioning Session [%s] not found.", message.h.resource.component[1]); - ogs_error("Client requested invalid Provisioning Session [%s]", message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Provisioning Session not found.", err, NULL, m5_serviceaccessinformation_api, app_meta)); - } else if (msaf_provisioning_session->serviceAccessInformation) { service_access_information = msaf_context_retrieve_service_access_information(message.h.resource.component[1]); if (service_access_information != NULL) { @@ -122,39 +110,36 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e) } else { char *err = NULL; asprintf(&err,"Service Access Information for the Provisioning Session [%s] not found.", message.h.resource.component[1]); - ogs_error("Client requested invalid Service Access Information for the Provisioning Session [%s]", message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL, m5_serviceaccessinformation_api, app_meta)); - - } } else { char *err = NULL; asprintf(&err,"Provisioning Session [%s] has no Service Access Information associated with it.", message.h.resource.component[1]); - ogs_error("Provisioning Session [%s] has no Service Access Information associated with it", message.h.resource.component[1]); + ogs_error("%s", err); ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Service Access Information not found.", err, NULL, m5_serviceaccessinformation_api, app_meta)); - } break; DEFAULT ogs_error("Invalid HTTP method [%s]", message.h.method); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 1, &message, "Invalid HTTP method.", message.h.method, NULL, NULL, app_meta)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, 1, &message, "Invalid HTTP method.", ogs_strdup(message.h.method), NULL, NULL, app_meta)); END break; DEFAULT ogs_error("Invalid resource name [%s]", message.h.resource.component[0]); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid resource name.", message.h.resource.component[0], NULL, NULL, app_meta)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid resource name.", ogs_strdup(message.h.resource.component[0]), NULL, NULL, app_meta)); END ogs_sbi_message_free(&message); break; DEFAULT ogs_error("Invalid API name [%s]", message.h.service.name); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid API name.", message.h.service.name, NULL, NULL, app_meta)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, &message, "Invalid API name.", ogs_strdup(message.h.service.name), NULL, NULL, app_meta)); END break; diff --git a/src/5gmsaf/msaf-mgmt-sm.c b/src/5gmsaf/msaf-mgmt-sm.c index 89180cf..dd9c72e 100644 --- a/src/5gmsaf/msaf-mgmt-sm.c +++ b/src/5gmsaf/msaf-mgmt-sm.c @@ -41,20 +41,13 @@ void msaf_maf_mgmt_state_final(ogs_fsm_t *s, msaf_event_t *e) void msaf_maf_mgmt_state_functional(ogs_fsm_t *s, msaf_event_t *e) { - int rv; - ogs_sbi_stream_t *stream = NULL; ogs_sbi_request_t *request = NULL; - - ogs_sbi_nf_instance_t *nf_instance = NULL; - ogs_sbi_subscription_data_t *subscription_data = NULL; - ogs_sbi_response_t *response = NULL; ogs_sbi_message_t message; - ogs_sbi_xact_t *sbi_xact = NULL; msaf_sm_debug(e); - if (!msaf_self()->server_name) msaf_context_server_name_set(); + if (!msaf_self()->server_name[0]) msaf_context_server_name_set(); char *nf_name = ogs_msprintf("5GMSdAF-%s", msaf_self()->server_name); const nf_server_app_metadata_t app_metadata = { MSAF_NAME, MSAF_VERSION, nf_name}; const nf_server_interface_metadata_t *maf_management_api = &maf_mgmt_api_metadata; @@ -84,7 +77,7 @@ void msaf_maf_mgmt_state_functional(ogs_fsm_t *s, msaf_event_t *e) DEFAULT ogs_error("Resource [%s] not found.", message.h.service.name); - ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_NOT_FOUND, 0, &message, "Not Found.", message.h.service.name, NULL, maf_management_api, app_meta)); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_NOT_FOUND, 0, &message, "Not Found.", ogs_strdup(message.h.service.name), NULL, maf_management_api, app_meta)); END break; diff --git a/src/5gmsaf/provisioning-session.c b/src/5gmsaf/provisioning-session.c index dfb35dc..5ec3fd0 100644 --- a/src/5gmsaf/provisioning-session.c +++ b/src/5gmsaf/provisioning-session.c @@ -128,7 +128,7 @@ msaf_provisioning_session_get_json(const char *provisioning_session_id) provisioning_session->server_certificate_ids = (OpenAPI_set_t*)OpenAPI_list_create(); for (cert_node=ogs_hash_first(msaf_provisioning_session->certificate_map); cert_node; cert_node=ogs_hash_next(cert_node)) { - ogs_debug("msaf_provisioning_session_get_json: Add cert %s", ogs_hash_this_key(cert_node)); + ogs_debug("msaf_provisioning_session_get_json: Add cert %s", (const char *)ogs_hash_this_key(cert_node)); OpenAPI_list_add(provisioning_session->server_certificate_ids, (void*)ogs_hash_this_key(cert_node)); } From b81c3fd9573cb1b1f7b0db65b963e323cbb213dc Mon Sep 17 00:00:00 2001 From: David Waring Date: Thu, 16 Mar 2023 11:48:42 +0000 Subject: [PATCH 29/48] Bump rt-common-shared HEAD to include Maf_Management.yaml --- subprojects/rt-common-shared | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/rt-common-shared b/subprojects/rt-common-shared index f256315..9a0598e 160000 --- a/subprojects/rt-common-shared +++ b/subprojects/rt-common-shared @@ -1 +1 @@ -Subproject commit f256315f116675b61e9c25e5eda295d9239fc764 +Subproject commit 9a0598e4b81f9dbfac6a4f48a267fa8c5bca63ee From b8d1962c63c0c8df03180ceffd137b95da56f0bf Mon Sep 17 00:00:00 2001 From: David Waring Date: Thu, 16 Mar 2023 12:50:37 +0000 Subject: [PATCH 30/48] Fix reporting on certificate awaiting upload. --- src/5gmsaf/certmgr.c | 2 +- src/5gmsaf/msaf-m1-sm.c | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/5gmsaf/certmgr.c b/src/5gmsaf/certmgr.c index a082d34..1b49bb6 100644 --- a/src/5gmsaf/certmgr.c +++ b/src/5gmsaf/certmgr.c @@ -98,7 +98,7 @@ msaf_certificate_t *server_cert_retrieve(const char *certid) ogs_assert(ret == 0); ogs_free(current); - if(!out_return_code){ + if(out_return_code == 0 || out_return_code == 4 || out_return_code == 8){ msaf_certificate = msaf_certificate_populate(certid, cert, out_return_code); ogs_assert(msaf_certificate); } diff --git a/src/5gmsaf/msaf-m1-sm.c b/src/5gmsaf/msaf-m1-sm.c index 5c225cb..3ea0eff 100644 --- a/src/5gmsaf/msaf-m1-sm.c +++ b/src/5gmsaf/msaf-m1-sm.c @@ -501,8 +501,15 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_sbi_response_t *response; const char *provisioning_session_cert; provisioning_session_cert = ogs_hash_get(msaf_provisioning_session->certificate_map, message.h.resource.component[3], OGS_HASH_KEY_STRING); + if(!provisioning_session_cert) { + char *err = NULL; + asprintf(&err,"Certificate [%s] not found in provisioning session [%s]", message.h.resource.component[3], message.h.resource.component[1]); + ogs_error("%s", err); + ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Certificate not found.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); + break; + } cert = server_cert_retrieve(message.h.resource.component[3]); - if(!cert || !provisioning_session_cert) { + if (!cert) { char *err = NULL; asprintf(&err,"Certificate [%s] management problem", message.h.resource.component[3]); ogs_error("%s", err); From 06302ce7cc840faeb849093b7a0cf751b15bb506 Mon Sep 17 00:00:00 2001 From: David Waring Date: Thu, 16 Mar 2023 13:13:39 +0000 Subject: [PATCH 31/48] Restore M3 client response handling. --- src/5gmsaf/msaf-sm.c | 635 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 635 insertions(+) diff --git a/src/5gmsaf/msaf-sm.c b/src/5gmsaf/msaf-sm.c index c0d3e6d..ef8ab51 100644 --- a/src/5gmsaf/msaf-sm.c +++ b/src/5gmsaf/msaf-sm.c @@ -17,7 +17,20 @@ #include "response-cache-control.h" #include "msaf-version.h" #include "msaf-sm.h" +#include "openapi/api/TS26512_M1_ContentHostingProvisioningAPI-info.h" +#include "openapi/api/M3_ContentHostingProvisioningAPI-info.h" +static const nf_server_interface_metadata_t +m1_contenthostingprovisioning_api_metadata = { + M1_CONTENTHOSTINGPROVISIONING_API_NAME, + M1_CONTENTHOSTINGPROVISIONING_API_VERSION +}; + +static const nf_server_interface_metadata_t +m3_contenthostingprovisioning_api_metatdata = { + M3_CONTENTHOSTINGPROVISIONING_API_NAME, + M3_CONTENTHOSTINGPROVISIONING_API_VERSION +}; void msaf_state_initial(ogs_fsm_t *s, msaf_event_t *e) { @@ -54,6 +67,8 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) msaf_context_server_name_set(); char *nf_name = ogs_msprintf("5GMSdAF-%s", msaf_self()->server_name); const nf_server_app_metadata_t app_metadata = { MSAF_NAME, MSAF_VERSION, nf_name}; + static const nf_server_interface_metadata_t *m3_contenthostingprovisioning_api = &m3_contenthostingprovisioning_api_metatdata; + static const nf_server_interface_metadata_t *m1_contenthostingprovisioning_api = &m1_contenthostingprovisioning_api_metadata; const nf_server_app_metadata_t *app_meta = &app_metadata; ogs_assert(s); @@ -202,6 +217,626 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) SWITCH(message.h.service.name) + CASE("3gpp-m3") + SWITCH(message.h.resource.component[0]) + CASE("content-hosting-configurations") + + msaf_application_server_state_node_t *as_state; + as_state = e->application_server_state; + ogs_assert(as_state); + + if (message.h.resource.component[1] && message.h.resource.component[2]) { + + if (!strcmp(message.h.resource.component[2],"purge")) { + + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) + purge_resource_id_node_t *purge_node = e->purge_node; + + if (response->status == 204 || response->status == 200) { + + purge_resource_id_node_t *content_hosting_cache, *next = NULL; + + if (response->status == 200) { + //parse the int in response body + //Add the integer to purge_node->m1_purge_info->purged_entries_total; + { + ogs_hash_index_t *hi; + for (hi = ogs_hash_first(request->http.headers); + hi; hi = ogs_hash_next(hi)) { + if (!ogs_strcasecmp(ogs_hash_this_key(hi), OGS_SBI_CONTENT_TYPE)) { + if (ogs_strcasecmp(ogs_hash_this_val(hi), "application/json")) { + char *err = NULL; + char *type = NULL; + type = (char *)ogs_hash_this_val(hi); + ogs_error("Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); + asprintf(&err, "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type); + + ogs_assert(true == nf_server_send_error(stream, 415, 2, &message, "Provisioning session does not exist.", err, NULL, m3_contenthostingprovisioning_api, app_meta)); + ogs_sbi_message_free(&message); + return; + } + } + } + } + + int purged_items_from_as = 0; + cJSON *entry; + cJSON *number_of_cache_entries = cJSON_Parse(response->http.content); + cJSON_ArrayForEach(entry, number_of_cache_entries) { + ogs_debug("Purged entries return %d\n", entry->valueint); + purged_items_from_as = entry->valueint; + + } + purge_node->m1_purge_info->purged_entries_total += purged_items_from_as; + + } + + + ogs_list_for_each_safe(&as_state->purge_content_hosting_cache, next, content_hosting_cache){ + if (purge_node->purge_regex) { + if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id) && !strcmp(content_hosting_cache->purge_regex, purge_node->purge_regex)) + break; + } else if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id)) { + break; + } + } + if(content_hosting_cache){ + ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); + ogs_debug("M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); + + purge_node->m1_purge_info->refs--; + ogs_debug(" After decrement, M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); + if(!purge_node->m1_purge_info->refs){ + // send M1 response with total from purge_node->m1_purge_info->purged_entries_total + // ogs_free(purge_node->m1_purge_info); + ogs_sbi_response_t *response; + cJSON *purged_entries_total_json = cJSON_CreateNumber(purge_node->m1_purge_info->purged_entries_total); + char *purged_entries_total = cJSON_Print(purged_entries_total_json); + response = ogs_sbi_response_new(); + response->http.content_length = strlen(purged_entries_total); + response->http.content = purged_entries_total; + response->status = 200; + ogs_sbi_header_set(response->http.headers, "Content-Type", "application/json"); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(purge_node->m1_purge_info->m1_stream, response)); + + if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); + if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); + if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); + ogs_free(content_hosting_cache); + } + msaf_application_server_state_log(&as_state->purge_content_hosting_cache, "Purge Content Hosting Cache list"); + + } + } + + + if((response->status == 404) || (response->status == 413) || (response->status == 414) || (response->status == 415) || (response->status == 422) || (response->status == 500) || (response->status == 503)) { + char *error; + purge_resource_id_node_t *content_hosting_cache, *next = NULL; + cJSON *purge_cache_err = NULL; + if(response->http.content){ + purge_cache_err = cJSON_Parse(response->http.content); + char *txt = cJSON_Print(purge_cache_err); + ogs_debug("txt:%s", txt); + } + + if(response->status == 404) { + + ogs_error("Error message from the Application Server [%s] with response code [%d]: Cache not found\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 413) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Pay load too large\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 414) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: URI too long\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 415) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Unsupported media type\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 422) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Unprocessable Entity\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 500) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Internal server error\n", as_state->application_server->canonicalHostname, response->status); + } else if(response->status == 503) { + ogs_error("Error message from the Application Server [%s] with response code [%d]: Service Unavailable\n", as_state->application_server->canonicalHostname, response->status); + } else { + + ogs_error("Application Server [%s] sent unrecognised response code [%d]", as_state->application_server->canonicalHostname, response->status); + } + + if (purge_node->purge_regex) { + error = ogs_msprintf("Application Server possibly encountered problem with regex %s", purge_node->purge_regex); + } else { + error = ogs_msprintf("Application Server unable to process the contained instructions"); + } + + + ogs_assert(true == nf_server_send_error( purge_node->m1_purge_info->m1_stream, + response->status, 3, &purge_node->m1_purge_info->m1_message, "Problem occured during cache purge", error, purge_cache_err, m1_contenthostingprovisioning_api, app_meta)); + + ogs_list_for_each_safe(&as_state->purge_content_hosting_cache, next, content_hosting_cache){ + if (purge_node->purge_regex) { + if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id) && !strcmp(content_hosting_cache->purge_regex, purge_node->purge_regex)) { + + ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); + ogs_debug("M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); + if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); + if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); + if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); + ogs_free(content_hosting_cache); + + } + } else if(!strcmp(content_hosting_cache->provisioning_session_id, purge_node->provisioning_session_id)) { + + ogs_list_remove(&as_state->purge_content_hosting_cache, content_hosting_cache); + ogs_debug("M1 List Purge refs: %d, Event Purge node refs: %d ", content_hosting_cache->m1_purge_info->refs, purge_node->m1_purge_info->refs); + if(content_hosting_cache->m1_purge_info) ogs_free(content_hosting_cache->m1_purge_info); + if (content_hosting_cache->provisioning_session_id) ogs_free(content_hosting_cache->provisioning_session_id); + if(content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex); + ogs_free(content_hosting_cache); + + } + } + ogs_free(error); + cJSON_Delete(purge_cache_err); + + } + + next_action_for_application_server(as_state); + break; + END + break; + + } + } else if (message.h.resource.component[1]) { + + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) + + if (response->status == 201) { + + ogs_debug("[%s] Method [%s] with Response [%d] recieved for Content Hosting Configuration [%s]", message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); + + resource_id_node_t *content_hosting_configuration; + ogs_list_for_each(&as_state->upload_content_hosting_configurations,content_hosting_configuration) { + if(!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) + break; + } + if(content_hosting_configuration) { + + ogs_debug("Removing %s from upload_content_hosting_configurations", content_hosting_configuration->state); + ogs_list_remove(&as_state->upload_content_hosting_configurations, content_hosting_configuration); + ogs_debug("Adding %s to current_content_hosting_configurations",content_hosting_configuration->state); + ogs_list_add(as_state->current_content_hosting_configurations, content_hosting_configuration); + } + + } + if(response->status == 405){ + ogs_error("Content Hosting Configuration resource already exist at the specified path\n"); + } + if(response->status == 413){ + ogs_error("Payload too large\n"); + } + if(response->status == 414){ + ogs_error("URI too long\n"); + } + if(response->status == 415){ + ogs_error("Unsupported media type\n"); + } + if(response->status == 500){ + ogs_error("Internal server error\n"); + } + if(response->status == 503){ + ogs_error("Service unavailable\n"); + } + next_action_for_application_server(as_state); + break; + CASE(OGS_SBI_HTTP_METHOD_PUT) + if(response->status == 200 || response->status == 204) { + + ogs_debug("[%s] Method [%s] with Response [%d] recieved for Content Hosting Configuration [%s]", message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); + resource_id_node_t *content_hosting_configuration; + ogs_list_for_each(&as_state->upload_content_hosting_configurations,content_hosting_configuration){ + if(!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) + break; + } + if(content_hosting_configuration) { + + ogs_debug("Removing %s from upload_content_hosting_configurations", content_hosting_configuration->state); + ogs_free(content_hosting_configuration->state); + ogs_list_remove(&as_state->upload_content_hosting_configurations, content_hosting_configuration); + ogs_free(content_hosting_configuration); + } + + } + if(response->status == 404){ + ogs_error("Not Found\n"); + } + if(response->status == 413){ + ogs_error("Payload too large\n"); + } + if(response->status == 414){ + ogs_error("URI too long\n"); + } + if(response->status == 415){ + ogs_error("Unsupported Media Type\n"); + } + if(response->status == 500){ + ogs_error("Internal Server Error\n"); + } + if(response->status == 503){ + ogs_error("Service Unavailable\n"); + } + next_action_for_application_server(as_state); + break; + CASE(OGS_SBI_HTTP_METHOD_DELETE) + if(response->status == 204) { + + ogs_debug("[%s] Method [%s] with Response [%d] recieved for Content Hosting Configuration [%s]", message.h.resource.component[0], message.h.method, response->status,message.h.resource.component[1]); + + resource_id_node_t *content_hosting_configuration, *next = NULL; + resource_id_node_t *delete_content_hosting_configuration, *node = NULL; + + if(as_state->current_content_hosting_configurations) { + + ogs_list_for_each_safe(as_state->current_content_hosting_configurations, next, content_hosting_configuration){ + + if(!strcmp(content_hosting_configuration->state, message.h.resource.component[1])) + break; + } + } + + if(content_hosting_configuration) { + + msaf_application_server_state_log(as_state->current_content_hosting_configurations, "Current Content Hosting Configurations"); + + ogs_debug("Removing %s from current_content_hosting_configurations", content_hosting_configuration->state); + ogs_free(content_hosting_configuration->state); + ogs_list_remove(as_state->current_content_hosting_configurations, content_hosting_configuration); + ogs_free(content_hosting_configuration); + msaf_application_server_state_log(as_state->current_content_hosting_configurations, "Current Content Hosting Configurations"); + } + + ogs_list_for_each_safe(&as_state->delete_content_hosting_configurations, node, delete_content_hosting_configuration) { + + if (!strcmp(delete_content_hosting_configuration->state, message.h.resource.component[1])) { + + msaf_application_server_state_log(&as_state->delete_content_hosting_configurations, "Delete Content Hosting Configurations"); + + ogs_debug("Destroying Content Hosting Configuration: %s", delete_content_hosting_configuration->state); + ogs_free(delete_content_hosting_configuration->state); + ogs_list_remove(&as_state->delete_content_hosting_configurations, delete_content_hosting_configuration); + ogs_free(delete_content_hosting_configuration); + + msaf_application_server_state_log(&as_state->delete_content_hosting_configurations, "Delete Content Hosting Configurations"); + } + } + + } + if(response->status == 404){ + ogs_error("Not Found\n"); + } + if(response->status == 413){ + ogs_error("Payload too large\n"); + } + if(response->status == 414){ + ogs_error("URI too long\n"); + } + if(response->status == 415){ + ogs_error("Unsupported Media Type\n"); + } + if(response->status == 500){ + ogs_error("Internal Server Error\n"); + } + if(response->status == 503){ + ogs_error("Service Unavailable\n"); + } + next_action_for_application_server(as_state); + break; + DEFAULT + ogs_error("Unknown M3 Content Hosting Configuration operation [%s]", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Content Hosting Configuration operation", message.h.resource.component[1], NULL, NULL, app_meta)); + break; + END + break; + } else { + cJSON *entry; + cJSON *chc_array = cJSON_Parse(response->http.content); + resource_id_node_t *current_chc; + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_GET) + + if(response->status == 200) { + + ogs_debug("[%s] Method [%s] with Response [%d] for Content Hosting Configuration operation [%s]", + message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); + + if (as_state->current_content_hosting_configurations == NULL) { + as_state->current_content_hosting_configurations = ogs_calloc(1,sizeof(*as_state->current_content_hosting_configurations)); + ogs_assert(as_state->current_content_hosting_configurations); + ogs_list_init(as_state->current_content_hosting_configurations); + + } else { + resource_id_node_t *next, *node; + ogs_list_for_each_safe(as_state->current_content_hosting_configurations, next, node) { + ogs_free(node->state); + ogs_list_remove(as_state->current_content_hosting_configurations, node); + ogs_free(node); + } + } + cJSON_ArrayForEach(entry, chc_array) { + char *id = strrchr(entry->valuestring, '/'); + if (id == NULL) { + id = entry->valuestring; + } else { + id++; + } + current_chc = ogs_calloc(1, sizeof(*current_chc)); + current_chc->state = ogs_strdup(id); + ogs_debug("Adding [%s] to the current Content Hosting Configuration list",current_chc->state); + ogs_list_add(as_state->current_content_hosting_configurations, current_chc); + } + + cJSON_Delete(chc_array); + } + if (response->status == 500){ + ogs_error("Received Internal Server error\n"); + } + if (response->status == 503) { + ogs_error("Service Unavailable\n"); + } + next_action_for_application_server(as_state); + break; + DEFAULT + char *err; + ogs_error("Unknown M3 Content Hosting Configuration operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + asprintf(&err, "Unknown M3 Content Hosting Configuration operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Content Hosting Configuration operation", err, NULL, NULL, app_meta)); + + break; + END + break; + } + next_action_for_application_server(as_state); + + break; + + CASE("certificates") + + msaf_application_server_state_node_t *as_state; + as_state = e->application_server_state; + ogs_assert(as_state); + if (message.h.resource.component[1]) { + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_POST) + if(response->status == 201) { + + ogs_debug("[%s] Method [%s] with Response [%d] recieved for certificate [%s]", message.h.resource.component[0], message.h.method, response->status, message.h.resource.component[1]); + + resource_id_node_t *certificate; + + //Iterate upload_certs and find match strcmp resource component 0 + ogs_list_for_each(&as_state->upload_certificates,certificate){ + if(!strcmp(certificate->state, message.h.resource.component[1])) + break; + } + if(certificate) { + + ogs_debug("Removing certificate [%s] from upload_certificates", certificate->state); + + ogs_list_remove(&as_state->upload_certificates, certificate); + + ogs_debug("Adding certificate [%s] to current_certificates", certificate->state); + + ogs_list_add(as_state->current_certificates, certificate); + // ogs_free(upload_cert_id); + } + } + if(response->status == 405){ + ogs_error("Server Certificate resource already exist at the specified path\n"); + } + if(response->status == 413){ + ogs_error("Payload too large\n"); + } + if(response->status == 414){ + ogs_error("URI too long\n"); + } + if(response->status == 415){ + ogs_error("Unsupported media type\n"); + } + if(response->status == 500){ + ogs_error("Internal server error\n"); + } + if(response->status == 503){ + ogs_error("Service unavailable\n"); + } + next_action_for_application_server(as_state); + break; + CASE(OGS_SBI_HTTP_METHOD_PUT) + if(response->status == 200 || response->status == 204) { + + ogs_debug("[%s] Method [%s] with Response [%d] recieved for certificate [%s]", message.h.resource.component[0], message.h.method, response->status,message.h.resource.component[1]); + + resource_id_node_t *certificate; + + msaf_application_server_state_log(&as_state->upload_certificates, "Upload Certificates"); + + //Iterate upload_certs and find match strcmp resource component 0 + ogs_list_for_each(&as_state->upload_certificates,certificate){ + + if(!strcmp(certificate->state, message.h.resource.component[1])) + break; + } + + if(!certificate){ + ogs_debug("Certificate %s not found in upload certificates", message.h.resource.component[1]); + } else { + ogs_debug("Removing certificate [%s] from upload_certificates", certificate->state); + ogs_free(certificate->state); + + ogs_list_remove(&as_state->upload_certificates, certificate); + ogs_free(certificate); + } + } + if(response->status == 404){ + ogs_error("Not Found\n"); + } + if(response->status == 413){ + ogs_error("Payload too large\n"); + } + if(response->status == 414){ + ogs_error("URI too long\n"); + } + if(response->status == 415){ + ogs_error("Unsupported Media Type\n"); + } + if(response->status == 500){ + ogs_error("Internal Server Error\n"); + } + if(response->status == 503){ + ogs_error("Service Unavailable\n"); + } + next_action_for_application_server(as_state); + break; + CASE(OGS_SBI_HTTP_METHOD_DELETE) + if(response->status == 204) { + + ogs_debug("[%s] Method [%s] with Response [%d] recieved for Certificate [%s]", message.h.resource.component[0], message.h.method, response->status,message.h.resource.component[1]); + + resource_id_node_t *certificate, *next = NULL; + resource_id_node_t *delete_certificate, *node = NULL; + + if(as_state->current_certificates) { + ogs_list_for_each_safe(as_state->current_certificates, next, certificate){ + + if(!strcmp(certificate->state, message.h.resource.component[1])) + break; + } + } + + if(certificate) { + + msaf_application_server_state_log(as_state->current_certificates, "Current Certificates"); + + ogs_debug("Removing certificate [%s] from current_certificates", certificate->state); + ogs_free(certificate->state); + + ogs_list_remove(as_state->current_certificates, certificate); + ogs_free(certificate); + msaf_application_server_state_log(as_state->current_certificates, "Current Certificates"); + } + + + ogs_list_for_each_safe(&as_state->delete_certificates, node, delete_certificate){ + + if(!strcmp(delete_certificate->state, message.h.resource.component[1])) { + msaf_application_server_state_log(&as_state->delete_certificates, "Delete Certificates"); + + ogs_debug("Destroying Certificate: %s", delete_certificate->state); + ogs_free(delete_certificate->state); + ogs_list_remove(&as_state->delete_certificates, delete_certificate); + ogs_free(delete_certificate); + msaf_application_server_state_log(&as_state->delete_certificates, "Delete Certificates"); + + } + } + } + if(response->status == 404){ + ogs_error("Not Found\n"); + } + if(response->status == 413){ + ogs_error("Payload too large\n"); + } + if(response->status == 414){ + ogs_error("URI too long\n"); + } + if(response->status == 415){ + ogs_error("Unsupported Media Type\n"); + } + if(response->status == 500){ + ogs_error("Internal Server Error\n"); + } + if(response->status == 503){ + ogs_error("Service Unavailable\n"); + } + next_action_for_application_server(as_state); + break; + DEFAULT + ogs_error("Unknown M3 certificate operation [%s]", message.h.resource.component[1]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 certificate operation.", message.h.resource.component[1], NULL, NULL, app_meta)); + break; + END + break; + } else { + cJSON *entry; + cJSON *cert_array = cJSON_Parse(response->http.content); + resource_id_node_t *current_cert; + SWITCH(message.h.method) + CASE(OGS_SBI_HTTP_METHOD_GET) + + if(response->status == 200) { + + ogs_debug("[%s] Method [%s] with Response [%d] received", + message.h.resource.component[0], message.h.method, response->status); + + if (as_state->current_certificates == NULL) { + as_state->current_certificates = ogs_calloc(1,sizeof(*as_state->current_certificates)); + ogs_assert(as_state->current_certificates); + ogs_list_init(as_state->current_certificates); + + } else { + resource_id_node_t *next, *node; + ogs_list_for_each_safe(as_state->current_certificates, next, node) { + + ogs_debug("Removing certificate [%s] from current_certificates", node->state); + + ogs_free(node->state); + ogs_list_remove(as_state->current_certificates, node); + ogs_free(node); + } + } + cJSON_ArrayForEach(entry, cert_array) { + char *id = strrchr(entry->valuestring, '/'); + if (id == NULL) { + id = entry->valuestring; + } else { + id++; + } + current_cert = ogs_calloc(1, sizeof(*current_cert)); + current_cert->state = ogs_strdup(id); + ogs_debug("Adding certificate [%s] to Current certificates", current_cert->state); + ogs_list_add(as_state->current_certificates, current_cert); + } + + cJSON_Delete(cert_array); + } + if (response->status == 500){ + ogs_error("Received Internal Server error"); + } + if (response->status == 503) { + ogs_error("Service Unavailable"); + } + next_action_for_application_server(as_state); + break; + DEFAULT + char *err; + ogs_error("Unknown M3 certificate operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + asprintf(&err, "Unsupported M3 Certificate operation [%s] with method [%s]", message.h.resource.component[1], message.h.method); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unknown M3 Certificate operation", err, NULL, NULL, app_meta)); + + break; + END + break; + } + next_action_for_application_server(as_state); + + break; + + DEFAULT + ogs_error("Unknown M3 operation [%s]", message.h.resource.component[0]); + ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 0, &message, "Unsupported M3 operation", message.h.resource.component[0], NULL, NULL, app_meta)); + break; + END + break; + CASE(OGS_SBI_SERVICE_NAME_NNRF_NFM) SWITCH(message.h.resource.component[0]) From 87a915a04706b675738633136f4cd66daf55e210 Mon Sep 17 00:00:00 2001 From: David Waring Date: Thu, 16 Mar 2023 13:56:26 +0000 Subject: [PATCH 32/48] Add more fields to CHC formatting. --- tools/python3/lib/rt_m1_client/types.py | 36 +++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tools/python3/lib/rt_m1_client/types.py b/tools/python3/lib/rt_m1_client/types.py index 6faf4ac..ade7a5c 100644 --- a/tools/python3/lib/rt_m1_client/types.py +++ b/tools/python3/lib/rt_m1_client/types.py @@ -210,10 +210,46 @@ def __formatDistributions(cls, chc: "ContentHostingConfiguration", indent: int = dists = [] for d in chc['distributionConfigurations']: s = f"{prefix}- URL: {d['baseURL']}" + if 'canonicalDomainName' in d: + s += f"\n{prefix} Canonical Domain Name: {d['canonicalDomainName']}" + if 'contentPreparationTemplateId' in d: + s += f"\n{prefix} Content Preparation Template: {d['contentPreparationTemplateId']}" if 'certificateId' in d: s += f"\n{prefix} Certificate: {d['certificateId']}" if 'domainNameAlias' in d: s += f"\n{prefix} Domain Name Alias: {d['domainNameAlias']}" + if 'pathRewriteRules' in d: + s += f"\n{prefix} Path Rewrite Rules:" + for prr in d['pathRewriteRules']: + s += f"\n{prefix} - {prr['requestPathPattern']} => {prr['mappedPath']}" + if 'cachingConfigurations' in d: + s += f"\n{prefix} Caching Configurations:" + for cc in d['cachingConfigurations']: + s += f"\n{prefix} - URL Pattern: {cc['urlPatternFilter']}" + if 'cachingDirectives' in cc: + cd = cc['cachingDirectives'] + s += f"\n{prefix} Directive:" + s += f"\n{prefix} no-cache={repr(cd['noCache'])}" + if 'maxAge' in cd: + s += f"\n{prefix} max-age={cd['maxAge']}" + if 'statusCodeFilters' in cd: + s += f"\n{prefix} filters=[{', '.join([str(i) for i in cd['statusCodeFilters']])}]" + if 'geoFencing' in d: + gf = d['geoFencing'] + s += f"\n{prefix} Geo-fencing({gf['locatorType']}):" + for l in gf['locators']: + s += f"\n{prefix} - {l}" + if 'urlSignature' in d: + us = d['urlSignature'] + s += f"\n{prefix} URL Signature:" + s += f"\n{prefix} - Pattern: {us['urlPattern']}" + s += f"\n{prefix} Token: {us['tokenName']}" + s += f"\n{prefix} Passphase name: {us['passphraseName']}" + s += f"\n{prefix} Passphase: {us['passphrase']}" + s += f"\n{prefix} Token Expiry name: {us['tokenExpiryName']}" + s += f"\n{prefix} Use IP Address?: {repr(us['useIPAddress'])}" + if 'ipAddressName' in us: + s += f"\n{prefix} IP Address name: {us['ipAddressName']}" dists += [s] return '\n'.join(dists) From 436366d864bb6549a6ef339dc0429189efb8970d Mon Sep 17 00:00:00 2001 From: David Waring Date: Thu, 16 Mar 2023 18:14:13 +0000 Subject: [PATCH 33/48] Add/improve code documentation. --- .../python3/lib/rt_m1_client/certificates.py | 60 ++++- tools/python3/lib/rt_m1_client/client.py | 235 ++++++++++-------- tools/python3/lib/rt_m1_client/data_store.py | 53 +++- 3 files changed, 227 insertions(+), 121 deletions(-) diff --git a/tools/python3/lib/rt_m1_client/certificates.py b/tools/python3/lib/rt_m1_client/certificates.py index f0b49a1..00b8b17 100644 --- a/tools/python3/lib/rt_m1_client/certificates.py +++ b/tools/python3/lib/rt_m1_client/certificates.py @@ -33,7 +33,7 @@ This module defines some classes that can be used by the `M1Session` class to provide certificate signing services. ''' -from typing import Optional +from typing import Optional, Tuple import OpenSSL @@ -79,16 +79,30 @@ class LocalCACertificateSigner(CertificateSigner): ''' def __init__(self, *args, data_store: Optional[DataStore] = None, local_ca_days: int = 365, temp_ca_days: int = 1, local_cert_days: int = 30, **kwargs): + '''Constructor + + Create a CertificateSigner that uses a locally generated CA to sign certificates. + + :param DataStore data_store: The DataStore to use to persist the CA key and certificate. + :param int local_ca_days: The number of days before expiry of the local CA in the data store. + :param int temp_ca_days: The number of days for the local CA if no DataStore is provided for persistence. + :param int local_cert_days: The number of days before expiry of signed certificates. + ''' super().__init__(self, data_store=data_store) - self.__ca_key = None - self.__ca = None - self.__local_ca_days = local_ca_days - self.__temp_ca_days = temp_ca_days - self.__local_cert_days = local_cert_days + self.__ca_key: Optional[OpenSSL.crypto.PKey] = None + self.__ca: Optional[OpenSSL.crypto.X509] = None + self.__local_ca_days: int = local_ca_days + self.__temp_ca_days: int = temp_ca_days + self.__local_cert_days: int = local_cert_days async def signCertificate(self, csr: str, *args, domain_name_alias: Optional[str] = None, **kwargs) -> str: '''Sign a CSR in PEM format and return the public X509 Certificate in PEM format + This will generate a public certificate from the *csr*, which is signed by the locally generated CA. + The certificate will have subjectAltNames defined for the SANs in the *csr*, the commonName and optionally the + *domain_name_alias*. The certificate will expire in the number of days indicated by the *local_cert_days* parameter + when an instance of this class was created. + :param str csr: A CSR in PEM format. :param str domain_name_alias: Optional domain name to add to the subjectAltNames in the final certificate. @@ -126,7 +140,21 @@ async def signCertificate(self, csr: str, *args, domain_name_alias: Optional[str x509.sign(ca_key, "sha256") return OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, x509).decode('utf-8') - async def __makeCACert(self, key: OpenSSL.crypto.PKey, cn: str, days: int = 365): + async def __makeCACert(self, key: OpenSSL.crypto.PKey, cn: str, days: int = 365) -> OpenSSL.crypto.X509: + '''Make a CA certificate + + The CA certificate will use the provided *key* for its public key (if a private key is provided the pubilc key will be + extracted). The *cn* parameter defines the common name for the CA certificate. The *days* parameter is used to set the + expiry date on the CA certificate. + + :meta private: + :param OpenSSL.crypto.PKey key: A public or private key to use for the public key of the CA certificate. + :param str cn: The commonName for the certificate subject and issuer. + :param int days: The number of days the CA certificate will be valid for. + + :return: a self signed X509 CA certificate. + :rtype: OpenSSL.crypto.X509 + ''' ca = OpenSSL.crypto.X509() ca_name = ca.get_subject() # TODO: Get these values from configured values @@ -146,7 +174,15 @@ async def __makeCACert(self, key: OpenSSL.crypto.PKey, cn: str, days: int = 365) ca.sign(key, 'sha256') return ca - async def __getLocalCA(self): + async def __getLocalCA(self) -> Tuple[OpenSSL.crypto.PKey, OpenSSL.crypto.X509]: + '''Get the locally generated CA + + This will create the locally generated CA if it doesn't already exist. + + :meta private: + :return: the CA key and CA public certificate. + :rtype: Tuple[OpenSSL.crypto.PKey, OpenSSL.crypto.X509] + ''' if self.__ca_key is None or self.__ca is None: if self.data_store: ca_key_pem = await self.data_store.get('ca-private') @@ -169,10 +205,10 @@ async def __getLocalCA(self): return self.__ca_key, self.__ca -DefaultCertificateSigner = LocalCACertificateSigner +DefaultCertificateSigner = LocalCACertificateSigner #: The default CertificateSigner __all__ = [ - "M1Error", - "M1ClientError", - "M1ServerError", + "CertificateSigner", + "LocalCACertificateSigner", + "DefaultCertificateSigner", ] diff --git a/tools/python3/lib/rt_m1_client/client.py b/tools/python3/lib/rt_m1_client/client.py index a9d8f34..2002e82 100644 --- a/tools/python3/lib/rt_m1_client/client.py +++ b/tools/python3/lib/rt_m1_client/client.py @@ -77,6 +77,8 @@ class ServerCertificateSigningRequestResponse(TagAndDateResponse, total=False): CertificateSigningRequestPEM: str class ContentProtocolsResponse(TagAndDateResponse, total=False): + '''Response containing a ContentProtocols object + ''' ProvisioningSessionId: ResourceId ContentProtocols: ContentProtocols @@ -88,8 +90,8 @@ def __init__(self, host_address: Tuple[str,int]): ''' Constructor - host_address (tuple(str,int)) - 5GMS Application Function to connect to as a tuple of - hostname/ip-addr and TCP port number. + :param Tuple[str,int] host_address: 5GMS Application Function to connect to as a tuple of hostname/ip-addr and TCP port + number. ''' self.__host_address = host_address self.__connection = None @@ -104,19 +106,15 @@ async def createProvisioningSession(self, provisioning_session_type: Provisionin ''' Create a provisioning session on the 5GMS Application Function - Parameters: - provisioning_session_type (ProvisioningSessionType) - The provisioning session type to create. - external_application_id (str) - The application ID of the external application requesting the new provisioning - session. - asp_id (optional str) - The Application Server Provider ID. + :param ProvisioningSessionType provisioning_session_type: The provisioning session type. + :param str external_application_id: The application ID of the external application requesting the new provisioning + session. + :param Optional[str] asp_id: The Application Server Provider ID. - Returns the ResourceId of the allocated provisioning session or None if there was an error. + :return: the ResourceId of the allocated provisioning session or None if there was an error. - Throws M1ClientError if there was a problem with the request and M1ServerError if there was - a server side issue preventing the creation of the provisioning session. + :raises M1ClientError: if there was a problem with the request + :raises M1ServerError: if there was a server side issue preventing the creation of the provisioning session. ''' self.__debug('M1Client.createProvisioningSession(%r, %r, asp_id=%r)', provisioning_session_type, external_application_id, asp_id) @@ -143,14 +141,13 @@ async def getProvisioningSessionById(self, ''' Get a provisioning session from the 5GMS Application Function - provisioning_session_id (ResourceId) - The provisioning session to find. + :param ResourceId provisioning_session_id: The provisioning session to find. - Returns a ProvisioningSession structure if the provisioning session was found, or None if - the provisioning session was not found. + :return: a ProvisioningSessionResponse structure if the provisioning session was found, or None if the provisioning + session was not found. - Throws M1ClientError if there was a problem with the request and M1ServerError if there was - a server side issue preventing the creation of the provisioning session. + :raises M1ClientError: if there was a problem with the request + :raises M1ServerError: if there was a server side issue preventing the creation of the provisioning session. ''' result = await self.__do_request('GET', '/provisioning-sessions/' + provisioning_session_id, '', @@ -171,13 +168,12 @@ async def destroyProvisioningSession(self, provisioning_session_id: ResourceId) ''' Destroy a provisioning session on the 5GMS Application Function - provisioning_session_id (ResourceId) - The provisioning session to find. + :param ResourceId provisioning_session_id: The provisioning session to find. - Returns True if a provisioning session was deleted or False if there was no action. + :return: True if a provisioning session was deleted or False if there was no action. - Throws M1ClientError if there was a problem with the request and M1ServerError if there was - a server side issue preventing the creation of the provisioning session. + :raise M1ClientError: if there was a problem with the request + :raise M1ServerError: if there was a server side issue preventing the creation of the provisioning session. ''' result = await self.__do_request('DELETE', '/provisioning-sessions/' + provisioning_session_id, '', @@ -195,10 +191,14 @@ async def createContentHostingConfiguration(self, provisioning_session_id: Resou ''' Create a content hosting configuration for a provisioning session - provisioning_session_id (ResourceId) - The provisioning session to create the content hosting configuration in. - content_hosting_configuration (ContentHostingConfiguration) - The content hosting configuration template to use. + :param ResourceId provisioning_session_id: The provisioning session to create the content hosting configuration in. + :param ContentHostingConfiguration content_hosting_configuration: The content hosting configuration template to use. + + :return: True if the ContentHostingConfiguration was accepted but the response was empty, False if the + ContentHostingConfiguration was not accepted or a ContentHostingConfigurationResponse if the + ContentHostingConfiguration was accepted and the AF updated version returned. + :raise M1ClientError: if there was a problem with the request. + :raise M1ServerError: if there was a server side issue preventing the creation of the provisioning session. ''' result = await self.__do_request('POST', f'/provisioning-sessions/{provisioning_session_id}/content-hosting-configuration', @@ -224,12 +224,15 @@ async def retrieveContentHostingConfiguration(self, provisioning_session_id: Res ''' Fetch the content hosting configuration for a provisioning session - provisioning_session_id (ResourceId) - The provisioning session to fetch the current content hosting configuration for. + :param ResourceId provisioning_session_id: The provisioning session to fetch the current content hosting configuration + for. - Returns None if the provisioning session does not exist, also returns None if the - provisioning session exists but does not have a content hosting configuration, - otherwise returns the content hosting configuration and metadata. + :return: None if the provisioning session does not exist, also returns None if the + provisioning session exists but does not have a content hosting configuration, + otherwise returns a ContentHostingConfigurationResponse. + + :raise M1ClientError: if there was a problem with the request. + :raise M1ServerError: if there was a server side issue preventing the creation of the provisioning session. ''' result = await self.__do_request('GET', f'/provisioning-sessions/{provisioning_session_id}/content-hosting-configuration', @@ -252,14 +255,16 @@ async def updateContentHostingConfiguration(self, provisioning_session_id: Resou ''' Update a content hosting configuration for a provisioning session - provisioning_session_id (ResourceId) - The provisioning session to update the current content hosting configuration for. - content_hosting_configuration (ContentHostingConfiguration) - The new content hosting configuration to apply. + :param ResourceId provisioning_session_id: The provisioning session to update the current content hosting configuration + for. + :param ContentHostingConfiguration content_hosting_configuration: The new content hosting configuration to apply. + + :return: a ContentHostingConfigurationResponse if the update succeeded and the new ContentHostingConfiguration was + returned by the M1 Server, or True if the update succeeded but no ContentHostingConfiguration was returned, + or False if the update failed. - Returns the content hosting configuration and metadata if the update succeeded and the new - content hosting configuration was returned, or True if the update succeeded but no - content hosting configuration was returned, or False if the update failed. + :raise M1ClientError: if there was a problem with the request. + :raise M1ServerError: if there was a server side issue preventing the creation of the provisioning session. ''' result = await self.__do_request('PUT', f'/provisioning-sessions/{provisioning_session_id}/content-hosting-configuration', @@ -285,14 +290,16 @@ async def patchContentHostingConfiguration(self, provisioning_session_id: Resour ''' Patch a content hosting configuration for a provisioning session using a JSON patch - provisioning_session_id (ResourceId) - The provisioning session to update the current content hosting configuration for. - patch (str) - The patch information in JSON patch format. + :param ResourceId provisioning_session_id: The provisioning session to update the current content hosting configuration + for. + :param str patch: The patch information in JSON patch format. - Returns the content hosting configuration and metadata if the patch succeeded and the new - content hosting configuration was returned, or True if the patch succeeded but no - content hosting configuration was returned, or False if the patch failed. + :return: a `ContentHostingConfigurationResponse` if the patch succeeded and the new ContentHostingConfiguration was + returned, or True if the patch succeeded but no ContentHostingConfiguration was returned, or False if the + patch failed. + + :raise M1ClientError: if there was a problem with the request. + :raise M1ServerError: if there was a server side issue preventing the creation of the provisioning session. ''' result = await self.__do_request('PATCH', f'/provisioning-sessions/{provisioning_session_id}/content-hosting-configuration', @@ -318,11 +325,12 @@ async def destroyContentHostingConfiguration(self, provisioning_session_id: Reso ''' Delete a content hosting configuration for a provisioning session - provisioning_session_id (ResourceId) - The provisioning session to remove the content hosting configuration for. + :param ResourceId provisioning_session_id: The provisioning session to remove the content hosting configuration for. + + :return: True if the ContentHostingConfiguration was deleted or False if the ContentHostingConfiguration did not exist. - Return True if the content hosting configuration was deleted or False if the content hosting - configuration did not exist. + :raise M1ClientError: if there was a problem with the request. + :raise M1ServerError: if there was a server side issue preventing the creation of the provisioning session. ''' result = await self.__do_request('DELETE', f'/provisioning-sessions/{provisioning_session_id}/content-hosting-configuration', @@ -339,12 +347,12 @@ async def purgeContentHostingCache(self, provisioning_session_id: ResourceId, ''' Purge cache entries for a provisioning session - provisioning_session_id (ResourceId) - The provisioning session to purge cache entries for. - filter_regex (str) - Optional regular expression to match the cache entries origin URL path. + :param ResourceId provisioning_session_id: The provisioning session to purge cache entries for. + :param Optional[str] filter_regex: Optional regular expression to match the cache entries origin URL path. - Return the number of purged entries, or None if no purge took place. + :return: the number of purged entries, or None if no purge took place. + :raise M1ClientError: if there was a problem with the request. + :raise M1ServerError: if there was a server side issue preventing the creation of the provisioning session. ''' body = '' if filter_regex is not None: @@ -364,20 +372,18 @@ async def purgeContentHostingCache(self, provisioning_session_id: ResourceId, async def createOrReserveServerCertificate(self, provisioning_session_id: ResourceId, csr=False) -> Optional[ServerCertificateSigningRequestResponse]: '''Create or reserve a server certificate for a provisioing session - provisioning_session_id (ResourceId) - The provisioning session to create the new certificate entry in. - csr (bool) - Whether to reserve a certificate and return the CSR PEM data. + :param ResourceId provisioning_session_id: The provisioning session to create the new certificate entry in. + :param bool csr: Whether to reserve a certificate and return the CSR PEM data. - If csr is True then this will reserve the certificate and request the - CSR PEM data be returned along side the Id of the newly reserved - certificate. + If *csr* is ``True`` then this will reserve the certificate and request the CSR PEM data be returned along side the Id + of the newly reserved certificate. - If csr is False or not provided then create a new certificate and just - return the new certificate Id. + If *csr* is ``False`` or not provided then create a new certificate and just return the new certificate Id. - Return a tuple containing the new certificate Id and an optional CSR - PEM data string. + :return: a `ServerCertificateSigningRequestResponse` containing the certificate id and metadata optionally with CSR PEM + data if *csr* was ``True``. + :raise M1ClientError: if there was a problem with the request. + :raise M1ServerError: if there was a server side issue preventing the creation of the provisioning session. ''' url = f'/provisioning-sessions/{provisioning_session_id}/certificates' @@ -402,10 +408,11 @@ async def createOrReserveServerCertificate(self, provisioning_session_id: Resour async def createServerCertificate(self, provisioning_session_id: ResourceId) -> ServerCertificateResponse: '''Create a new certificate for a provisioning session - provisioning_session_id (ResourceId) - The provisioning session to create the new certificate entry in. + :param ResourceId provisioning_session_id: The provisioning session to create the new certificate entry in. - Returns the certificate Id of the newly created certificate. + :return: a ServerCertificateResponse for the newly created certificate. + :raise M1ClientError: if there was a problem with the request. + :raise M1ServerError: if there was a server side issue preventing the creation of the provisioning session. ''' result = await self.createOrReserveServerCertificate(provisioning_session_id, csr=False) return result @@ -413,10 +420,12 @@ async def createServerCertificate(self, provisioning_session_id: ResourceId) -> async def reserveServerCertificate(self, provisioning_session_id: ResourceId) -> ServerCertificateSigningRequestResponse: '''Reserve a certificate for a provisioning session and get the CSR PEM - provisioning_session_id (ResourceId) - The provisioning session to create the new certificate entry in. + :param ResourceId provisioning_session_id: The provisioning session to create the new certificate entry in. - Returns a CSR as a PEM string plus metadata for the reserved certificate. + :return: a `ServerCertificateSigningRequestResponse` containing the CSR as a PEM string plus metadata for the reserved + certificate. + :raise M1ClientError: if there was a problem with the request. + :raise M1ServerError: if there was a server side issue preventing the creation of the provisioning session. ''' result = await self.createOrReserveServerCertificate(provisioning_session_id, csr=True) if result is None or 'CertificateSigningRequestPEM' not in result: @@ -426,16 +435,13 @@ async def reserveServerCertificate(self, provisioning_session_id: ResourceId) -> async def uploadServerCertificate(self, provisioning_session_id: ResourceId, certificate_id: ResourceId, pem_data: str) -> bool: '''Upload the signed public certificate for a reserved certificate - provisioning_session_id (ResourceId) - The provisioning session the certificate was reserved for. - certificate_id (ResourceId) - The certificate Id of the reserved certificate. - pem_data (str) - A string containing the PEM data for the public certificate to - upload. + :param ResourceId provisioning_session_id: The provisioning session the certificate was reserved for. + :param ResourceId certificate_id: The certificate Id of the reserved certificate. + :param str pem_data: A string containing the PEM data for the public certificate to upload. - Returns True if successful or False if the certificate has already been - uploaded. + :return: ``True`` if successful or ``False`` if the certificate has already been uploaded. + :raise M1ClientError: if there was a problem with the request. + :raise M1ServerError: if there was a server side issue preventing the creation of the provisioning session. ''' result = await self.__do_request('PUT', f'/provisioning-sessions/{provisioning_session_id}/certificates/{certificate_id}', @@ -448,15 +454,14 @@ async def uploadServerCertificate(self, provisioning_session_id: ResourceId, cer async def retrieveServerCertificate(self, provisioning_session_id: ResourceId, certificate_id: ResourceId) -> Optional[ServerCertificateResponse]: '''Retrieve the public certificate for a given certificate Id - provisioning_session_id (ResourceId) - The provisioning session for the certificate. - certificate_id (ResourceId) - The certificate Id of the certificate. + :param ResourceId provisioning_session_id: The provisioning session for the certificate. + :param ResourceId certificate_id: The certificate Id of the certificate. - Returns the PEM data for the public certificate and its metadata or - None if the certificate is reserved and awaiting upload. + :return: a ServerCertificateResponse containing the PEM data for the public certificate and its metadata or ``None`` + if the certificate is reserved and awaiting upload. - Raises M1ClientError with status_code 404 if the certificate is not found. + :raise M1ClientError: if there was a problem with the request or the certificate was not found. + :raise M1ServerError: if there was a server side issue preventing the creation of the provisioning session. ''' result = await self.__do_request('GET', f'/provisioning-sessions/{provisioning_session_id}/certificates/{certificate_id}', @@ -477,12 +482,12 @@ async def retrieveServerCertificate(self, provisioning_session_id: ResourceId, c async def destroyServerCertificate(self, provisioning_session_id: ResourceId, certificate_id: ResourceId) -> bool: '''Delete a certificate. - provisioning_session_id (ResourceId) - The provisioning session for the certificate. - certificate_id (ResourceId) - The certificate Id of the certificate. + :param ResourceId provisioning_session_id: The provisioning session for the certificate. + :param ResourceId certificate_id: The certificate Id of the certificate. - Returns True if the certificate has been deleted. + :return: ``True`` if the certificate has been deleted. + :raise M1ClientError: if there was a problem with the request. + :raise M1ServerError: if there was a server side issue preventing the creation of the provisioning session. ''' result = await self.__do_request('DELETE', f'/provisioning-sessions/{provisioning_session_id}/certificates/{certificate_id}', @@ -496,10 +501,12 @@ async def destroyServerCertificate(self, provisioning_session_id: ResourceId, ce async def retrieveContentProtocols(self, provisioning_session_id: ResourceId) -> Optional[ContentProtocolsResponse]: '''Get the ContentProtocols information for the provisioning session - provisioning_session_id (ResourceId) - The provisioning session to get the ContentProtocols for. + :param ResourceId provisioning_session_id: The provisioning session to get the ContentProtocols for. - Returns a ContentProtocols structure and metadata. + :return: a `ContentProtocolsResponse` containing the ContentProtocols structure and metadata or None if the + provisioning session was not found. + :raise M1ClientError: if there was a problem with the request. + :raise M1ServerError: if there was a server side issue preventing the creation of the provisioning session. ''' result = await self.__do_request('GET', f'/provisioning-sessions/{provisioning_session_id}/protocols', @@ -558,6 +565,16 @@ async def retrieveContentProtocols(self, provisioning_session_id: ResourceId) -> async def __do_request(self, method: str, url_suffix: str, body: Union[str,bytes], content_type: str, headers: Optional[dict] = None) -> Dict[str,Any]: '''Send a request to the 5GMS Application Function + + :meta private: + :param str method: The HTTP method for the request. + :param str url_suffix: The URL path suffix for the request after the protocol and version identifiers. + :param Union[str,bytes] body: The body of the request as a `str` or `bytes`. + :param str content_type: The content type to use in the ``Content-Type`` header of the request. + :param Optional[dict] headers: Extra headers to go along with the request. + :return: a `dict` with 3 entries ``status_code``, ``body`` and ``headers`` representing the HTTP response status code, + the response message body and the response headers. + :raise M1ServerError: if communication with the AF failed. ''' # pylint: disable=too-many-arguments if isinstance(body, str): @@ -578,6 +595,14 @@ async def __do_request(self, method: str, url_suffix: str, body: Union[str,bytes def __default_response(self, result: Dict[str,Any]) -> None: '''Handle default actions for all responses from the 5GMS Application Function + + This will raise exceptions for 4XX and 5XX response codes. + + :meta private: + :param Dict[str,Any] result: The result as returned by `__do_request`. + + :raise M1ClientError: if there was a problem with the request. + :raise M1ServerError: if there was a server side issue preventing the creation of the provisioning session. ''' if result['status_code'] >= 400 and result['status_code'] < 500: raise M1ClientError(reason='M1 operation failed: '+str(result['body']), @@ -588,6 +613,14 @@ def __default_response(self, result: Dict[str,Any]) -> None: @staticmethod def __tag_and_date(result: Dict[str,Any]) -> TagAndDateResponse: + '''Get the response message standard metadata + + This will extract metadata from ``ETag``, ``Last-Modified`` and ``Cache-Control`` headers. + + :param Dict[str,Any] result: The result as returned by `__do_request`. + + :return: the base TagAndDateResponse structure for all response messages. + ''' # Get ETag ret = {'ETag': result['headers'].get('etag')} # Get Last-Modified as a datetime.datetime @@ -623,7 +656,13 @@ def __tag_and_date(result: Dict[str,Any]) -> TagAndDateResponse: ret['Cache-Until'] = cc return ret - def __debug(self, *args, **kwargs): + def __debug(self, *args, **kwargs) -> None: + '''Output a debug message + + :meta private: + :param args: Positional arguments to pass to `logger.debug()`. + :param kwargs: Keyword arguments to pass to `logger.debug()`. + ''' self.__log.debug(*args, **kwargs) __all__ = [ diff --git a/tools/python3/lib/rt_m1_client/data_store.py b/tools/python3/lib/rt_m1_client/data_store.py index abb7aa1..9834b2f 100644 --- a/tools/python3/lib/rt_m1_client/data_store.py +++ b/tools/python3/lib/rt_m1_client/data_store.py @@ -33,6 +33,7 @@ represented in JSON notation as a set of files. ''' import aiofiles +import aiofiles.os import json import logging import os @@ -42,13 +43,46 @@ class DataStore: '''DataStore base class ''' + def __await__(self): + '''Implement ``await`` on object creation + + This allows derived `DataStore` objects to perform asynchronous tasks on object instantiation. + + For example:: + data_store = await DataStore() + + This will await the `asyncInit()` method of this object. + ''' + return self.asyncInit().__await__() + + async def asyncInit(self): + '''Asynchronous DataStore initialisation + + Implementations should override this method to perform any object initialisation requiring asynchronous operations. + + This must always return *self*. + + :return: self + ''' + return self + async def get(self, key: str, default: Any = None) -> Any: '''Get a persisted value by key name + + :param str key: The key name to retrieve the `DataStore` value for. + :param default: The default value to return if the key does not exist in the `DataStore`. + + :return: The value of the retrieved key or the *default* value. ''' raise NotImplementedError('DataStore implementation should override this method') async def set(self, key: str, value: Any) -> bool: '''Store a persisted value using the key name + + :param str key: The key name to set a value for. + :param value: The value to set. + + :return: ``True`` if the value was set in the `DataStore` or ``False`` if there was a failure. ''' raise NotImplementedError('DataStore implementation should override this method') @@ -59,25 +93,22 @@ class JSONFileDataStore(DataStore): ''' def __init__(self, data_store_dir: str): self.__dir = data_store_dir - if not os.path.exists(self.__dir): - os.makedirs(self.__dir) - if not os.path.isdir(self.__dir): - raise RuntimeError(f'{self.__dir} is not a directory') - def __await__(self): - return self.__self().__await__() - - async def __self(self): + async def asyncInit(self): + if not await aiofiles.os.path.exists(self.__dir): + await aiofiles.os.makedirs(self.__dir) + if not await aiofiles.os.path.isdir(self.__dir): + raise RuntimeError(f'{self.__dir} is not a directory') return self async def get(self, key: str, default: Any = None) -> Any: '''Get a persisted value by key name ''' json_file = os.path.join(self.__dir, f'{key}.json') - if not os.path.exists(json_file) or not os.path.isfile(json_file): + if not await aiofiles.os.path.exists(json_file) or not await aiofiles.os.path.isfile(json_file): return default - with open(json_file, 'r') as json_in: - val = json.load(json_in) + async with aiofiles.open(json_file, mode='r') as json_in: + val = json.loads(await json_in.read()) return val async def set(self, key: str, value: Any) -> bool: From 6e29bba8a7d34862a480f97e941ea6cecc143c2a Mon Sep 17 00:00:00 2001 From: David Waring Date: Fri, 17 Mar 2023 17:12:46 +0000 Subject: [PATCH 34/48] Improve code documentation --- tools/python3/lib/rt_m1_client/data_store.py | 24 ++ tools/python3/lib/rt_m1_client/exceptions.py | 30 ++- tools/python3/lib/rt_m1_client/session.py | 259 +++++++++++++++++-- tools/python3/lib/rt_m1_client/types.py | 98 +++++-- tools/python3/m1_session_cli.py | 19 +- 5 files changed, 377 insertions(+), 53 deletions(-) diff --git a/tools/python3/lib/rt_m1_client/data_store.py b/tools/python3/lib/rt_m1_client/data_store.py index 9834b2f..21ed388 100644 --- a/tools/python3/lib/rt_m1_client/data_store.py +++ b/tools/python3/lib/rt_m1_client/data_store.py @@ -92,9 +92,23 @@ class JSONFileDataStore(DataStore): This class implements a DataStore as a set of files containing JSON. ''' def __init__(self, data_store_dir: str): + '''Constructor + + :param str data_store_dir: The directory path to use for the JSON file data store. + + Please note that this object should be instantiated using ``await JSONFileDataStore(data_store_dir)`` as it has + asynchronous initialisation to perform. + ''' self.__dir = data_store_dir async def asyncInit(self): + '''Asynchronous JSONFileDataStore initialisation + + This will ensure that the data store directory for JSON files exists during instantiation. + + :return: self + :raise RuntimeError: if the data store path already exists but is not a directory. + ''' if not await aiofiles.os.path.exists(self.__dir): await aiofiles.os.makedirs(self.__dir) if not await aiofiles.os.path.isdir(self.__dir): @@ -103,6 +117,11 @@ async def asyncInit(self): async def get(self, key: str, default: Any = None) -> Any: '''Get a persisted value by key name + + :param str key: The key name to retrieve the `DataStore` value for. + :param default: The default value to return if the *key* does not exist in the `DataStore`. + + :return: The value of the retrieved key or the *default* value. ''' json_file = os.path.join(self.__dir, f'{key}.json') if not await aiofiles.os.path.exists(json_file) or not await aiofiles.os.path.isfile(json_file): @@ -113,6 +132,11 @@ async def get(self, key: str, default: Any = None) -> Any: async def set(self, key: str, value: Any) -> bool: '''Store a persisted value using the key name + + :param str key: The key name to set a value for. + :param value: The value to set. + + :return: ``True`` if the value was set in the `DataStore` or ``False`` if there was a failure. ''' json_file = os.path.join(self.__dir, f'{key}.json') async with aiofiles.open(json_file, mode='w') as json_out: diff --git a/tools/python3/lib/rt_m1_client/exceptions.py b/tools/python3/lib/rt_m1_client/exceptions.py index d8a7b13..0b2e41c 100644 --- a/tools/python3/lib/rt_m1_client/exceptions.py +++ b/tools/python3/lib/rt_m1_client/exceptions.py @@ -48,9 +48,14 @@ from .types import ProblemDetail, InvalidParam -def format_invalid_param(inv_param: InvalidParam): +def format_invalid_param(inv_param: InvalidParam) -> str: ''' Format an InvalidParams entry for display + + :param InvalidParam inv_param: The `InvalidParam` to generate a formatted string for. + + :return: a `str` containing the invalid parameter name optionally followed by the reason. + :rtype: str ''' ret: str = inv_param['param'] if 'reason' in inv_param and inv_param['reason'] is not None: @@ -64,9 +69,20 @@ class M1Error(Exception): ''' def __init__(self, reason: str, # pylint: disable=useless-super-delegation status_code: Optional[int] = None, problem_detail: Optional[ProblemDetail] = None): + '''Constructor + + :param str reason: The reason for the error. + :param Optional[int] status_code: An optional HTTP status code to associate with the error. + :param Optional[ProblemDetail] problem_detail: An optional `ProblemDetail` to associate with the error. + ''' super().__init__(reason, status_code, problem_detail) def __str__(self) -> str: + '''String representation of the error + + :return: a formatted string representation of the `M1Error`. + ''' + # If a ProblemDetail is available use it if self.args[2] is not None: problem = self.args[2] ret: str = '' @@ -80,18 +96,24 @@ def __str__(self) -> str: ret += '\nInvalid Parameters:\n'+'\n'.join( [' '+format_invalid_param(p) for p in problem['invalidParams']]) return ret + # Else if an HTTP status code is available use "[status_code] reason" as the format if self.args[1] is not None: return f'[{self.args[1]}] {self.args[0]}' + # Otherwise just use the reason string return self.args[0] def __repr__(self) -> str: - return f'{self.__class__.__name__}(reason={self.args[0]!r}, status_code={self.args[1]!r})' + '''Format a `str` representation of this error + + :return: The error formatted as a constructor for this error. + ''' + return f'{self.__class__.__name__}(reason={self.args[0]!r}, status_code={self.args[1]!r}, problem_detail={self.args[2]!r})' class M1ClientError(M1Error): '''Raised when there was a client side problem during M1 operations This error is raised when there was a problem with the client request - detected either by this class or by the M1 server (5GMS Application + detected either by this class, or by the M1 server (5GMS Application Function) responding with a 4XX response. The request should not be repeated in this form as it will fail again. @@ -103,7 +125,7 @@ class M1ServerError(M1Error): This represents 5XX error responses from the M1 server (5GMS Application Function). - The request may be repeated. + The request may be repeated at a future date and may or may not work then. ''' __all__ = [ diff --git a/tools/python3/lib/rt_m1_client/session.py b/tools/python3/lib/rt_m1_client/session.py index d050ca1..bfa136e 100644 --- a/tools/python3/lib/rt_m1_client/session.py +++ b/tools/python3/lib/rt_m1_client/session.py @@ -36,7 +36,7 @@ import datetime import importlib import logging -from typing import Optional, Union, Tuple, Dict, Any, TypedDict, List +from typing import Optional, Union, Tuple, Dict, Any, TypedDict, List, Iterable import OpenSSL @@ -52,10 +52,20 @@ class M1Session: '''M1 Session management class =========================== - This class is used as the top level class to manage a communication session - with the 5GMS Application Function. + This class is used as the top level class to manage a communication session with the 5GMS Application Function. It will + communicate using the `M1Client` class with the M1 Server (5GMS Application Function) and cache the results to improve + efficiency. It can also use a `DataStore` to provide persistence of information across different sessions, and can use a + `CertificateSigner` to perform signing of certificates when ``domainNameAlias`` is used. ''' + def __init__(self, host_address: Tuple[str,int], persistent_data_store: Optional[DataStore] = None, certificate_signer: Optional[Union[CertificateSigner,type,str]] = None): + '''Constructor + + :param host_address: A tuple containing the M1 server (5GMS Application Function) hostname/ip-address and TCP port number + to contact it at. + :param persistent_data_store: A `DataStore` object to use to provide persistent storage. + :param certificate_signer: A `CertificateSigner` to use when signing certificates with extra domain names. This can be either a `str` containing the full Python class name, a `CertificateSigner` class to instantiate if needed, or an instance of a `CertificateSigner` to use. If not given then ``rt_m1_client.certificates.DefaultCertificateSigner`` is used. + ''' self.__m1_host = host_address self.__data_store_dir = persistent_data_store self.__cert_signer = certificate_signer @@ -66,21 +76,35 @@ def __init__(self, host_address: Tuple[str,int], persistent_data_store: Optional self.__log = logging.getLogger(__name__ + '.' + self.__class__.__name__) def __await__(self): + '''``await`` provider for asynchronous instansiation. + ''' return self.__asyncInit().__await__() async def __asyncInit(self): + '''Asynchronous object instantiation + + Loads previous state from the DataStore. + + :meta private: + :return: self + ''' await self.__reloadFromDataStore() return self # Provisioning Session Management - async def provisioningSessionIds(self): + async def provisioningSessionIds(self) -> Iterable: '''Get the list of current known provisioning session ids + + :return: an iterable for the provisioning session ids. ''' return self.__provisioning_sessions.keys() async def provisioningSessionProtocols(self, provisioning_session_id: ResourceId) -> Optional[ContentProtocols]: '''Get the ContentProtocols for the existing provisioning session + + :param ResourceId provisioning_session_id: The provisioning session to get `ContentProtocols` for. + :return: a `ContentProtocols` for the provisioning session or ``None`` if the `ContentProtocols` could not be found. ''' if provisioning_session_id not in self.__provisioning_sessions: return None @@ -89,6 +113,9 @@ async def provisioningSessionProtocols(self, provisioning_session_id: ResourceId async def provisioningSessionCertificateIds(self, provisioning_session_id: ResourceId) -> Optional[List[ResourceId]]: '''Get the list of certificate Ids for a provisioning session + + :param ResourceId provisioning_session_id: The provisioning session id to get the certificate ids for. + :return: a list of certificate ids associated with the *provisioning_session_id* or ``None`` if they could not be found. ''' if provisioning_session_id not in self.__provisioning_sessions: return None @@ -101,8 +128,9 @@ async def provisioningSessionCertificateIds(self, provisioning_session_id: Resou async def provisioningSessionContentHostingConfiguration(self, provisioning_session_id: ResourceId) -> Optional[ContentHostingConfiguration]: '''Get the ContentHostingConfiguration associated with the provisioning session - Returns None if the provisioning session does not exist or if there is no ContentHostingConfiguration associated with the - provisioning session. + :param ResourceId provisioning_session_id: The provisioning session id to get the `ContentHostingConfiguration` for. + :return: ``None`` if the provisioning session does not exist or if there is no `ContentHostingConfiguration` associated + with the provisioning session, otherwise return the `ContentHostingConfiguration`. ''' if provisioning_session_id not in self.__provisioning_sessions: return None @@ -116,6 +144,12 @@ async def provisioningSessionContentHostingConfiguration(self, provisioning_sess return chc async def provisioningSessionDestroy(self, provisioning_session_id: ResourceId) -> Optional[bool]: + '''Destroy a provisioning session + + :param provisioning_session_id: The provisioning session id of the session to destroy. + :return: ``True`` if the provisioning session was destroyed, ``False`` if it could not be destroyed or ``None`` if the + provisioning session does not exist. + ''' if provisioning_session_id not in self.__provisioning_sessions: return None await self.__connect() @@ -124,15 +158,33 @@ async def provisioningSessionDestroy(self, provisioning_session_id: ResourceId) del self.__provisioning_sessions[provisioning_session_id] if self.__data_store_dir: await self.__data_store_dir.set('provisioning_sessions', list(self.__provisioning_sessions.keys())) + return True + return False + + async def provisioningSessionCreate(self, prov_type: ProvisioningSessionType, app_id: ApplicationId, asp_id: Optional[ApplicationId] = None) -> Optional[ResourceId]: + '''Create a provisioning session + + The *prov_type* should be `rt_m1_client.types.PROVISIONING_SESSION_TYPE_DOWNLINK` or + `rt_m1_client.types.PROVISIONING_SESSION_TYPE_UPLINK`. The *app_id* is the mandatory external application id, and the + *asp_id* is the optional ASP identfier. + + :param prov_type: The provisioning session type, either `PROVISIONING_SESSION_TYPE_DOWNLINK` or + `PROVISIONING_SESSION_TYPE_UPLINK`. + :param app_id: This is the External Application Id. + :param asp_id: This is the optional Application Service Provider Id. - async def provisioningSessionCreate(self, prov_type: ProvisioningSessionType, app_id: ApplicationId, asp_id: ApplicationId): + :return: the provisioning session id for the new provisioning session or ``None`` if the `ProvisioningSession` could not + be created. + ''' await self.__connect() - prov_sess_resp: ProvisioningSessionResponse = await self.__m1_client.createProvisioningSession(prov_type, app_id, asp_id) + prov_sess_resp: Optional[ProvisioningSessionResponse] = await self.__m1_client.createProvisioningSession(prov_type, app_id, asp_id) if prov_sess_resp is None: self.__log.debug("provisioningSessionCreate: no response") return None ps_id = prov_sess_resp['ProvisioningSessionId'] + # Register the provisioning session id self.__provisioning_sessions[ps_id] = None + # Store in the `DataStore` if available if self.__data_store_dir: await self.__data_store_dir.set('provisioning_sessions', list(self.__provisioning_sessions.keys())) return ps_id @@ -140,6 +192,11 @@ async def provisioningSessionCreate(self, prov_type: ProvisioningSessionType, ap # Certificates management async def certificateIds(self, provisioning_session_id: ResourceId) -> Optional[List[ResourceId]]: + '''Get a list of certificate Ids + + :param provisioning_session_id: The provisioning session id to retrieve certificate ids for. + :return: a list of certificate ids or ``None`` if the provisioning session doesn't exist or cannot be retrieved. + ''' if provisioning_session_id not in self.__provisioning_sessions: return None await self.__cacheProvisioningSession(provisioning_session_id) @@ -149,6 +206,15 @@ async def certificateIds(self, provisioning_session_id: ResourceId) -> Optional[ return ps['serverCertificateIds'] async def certificateCreate(self, provisioning_session_id: ResourceId) -> Optional[ResourceId]: + '''Create a new certificate + + This creates a new M1 Server signed certificate in the provisioning session and returns the new certificate id. + + :param provisioning_session_id: The provisioning session to create the new certificate in. + + :return: the certificate id of the new certificate or ``None`` if the provisioning session does not exist or if there was + no response from the M1 Server. + ''' if provisioning_session_id not in self.__provisioning_sessions: return None await self.__connect() @@ -173,21 +239,43 @@ async def certificateCreate(self, provisioning_session_id: ResourceId) -> Option return cert_id async def certificateGet(self, provisioning_session_id: ResourceId, certificate_id: ResourceId) -> Optional[str]: + '''Retrieve a public certificate + + :param provisioning_session_id: The provisioning session id to use to look up the certificate. + :param certificate_id: The certificate id for the certificate in the provisioning session. + + :return: The PEM string for the public certificate or ``None`` if the certificate could not be found. + ''' ret_err = None if provisioning_session_id not in self.__provisioning_sessions: return None try: await self.__cacheCertificates(provisioning_session_id) except M1Error as err: + # This error may happen for a different certificate, so just remember it for now ret_err = err ps = self.__provisioning_sessions[provisioning_session_id] + # If the certificate does not exist return None if 'certificates' not in ps or ps['certificates'] is None or certificate_id not in ps['certificates']: return None + # If there was an error caching certificates and this certificate failed to cache then forward the exception if ret_err is not None and ps['certificates'][certificate_id]['servercertificate'] is None: raise ret_err + # Return the cached certificate return ps['certificates'][certificate_id]['servercertificate'] async def certificateNewSigningRequest(self, provisioning_session_id: ResourceId) -> Optional[Tuple[ResourceId,str]]: + '''Create a new CSR for a provisioning session + + This reserves a new certificate in the provisioning session and returns the new certificate id and CSR PEM string. + It is the responsibility of the caller to generate a signed public certificate from the CSR and post it back to the M1 + Server using the `certificateSet` method. + + :param provisioning_session_id: The provisioning session to reserve the new certificate in. + + :return: a tuple of certificate id and CSR PEM string for the new certificate or ``None`` if the provisioning session does + not exist or if there was no response from the M1 Server. + ''' if provisioning_session_id not in self.__provisioning_sessions: return None await self.__connect() @@ -205,6 +293,19 @@ async def certificateNewSigningRequest(self, provisioning_session_id: ResourceId return (cert_id,cert_resp['CertificateSigningRequestPEM']) async def certificateSet(self, provisioning_session_id: ResourceId, certificate_id: ResourceId, pem: str) -> Optional[bool]: + '''Set the public certificate for a reserved certificate in a provisioning session + + This is used to provide a signed public certificate to the M1 Server after reserving the certificate with + `certificateNewSigningRequest`. This can only be done once per certificate reservation, once the public certificate is set + then further updates to it are not allowed. + + :param provisioning_session_id: The provisioning session id of the provisioning session to upload the certificate to. + :param certificate_id: The certificate id in the provisioning session to upload the certificate to. + :param pem: The public certificate as a PEM string to be uploaded. + + :return: ``True`` if the certificate was set, ``False`` if it has already been set and ``None`` if the provisioning + session or certificate id was not found. + ''' if provisioning_session_id not in self.__provisioning_sessions: return None await self.__connect() @@ -213,6 +314,14 @@ async def certificateSet(self, provisioning_session_id: ResourceId, certificate_ # ContentHostingConfiguration methods async def contentHostingConfigurationCreate(self, provisioning_session: ResourceId, chc: ContentHostingConfiguration) -> bool: + '''Store a new `ContentHostingConfiguration` for a provisioning session + + :param provisioning_session: The provisioning session id of the provisioning session to set the + `ContentHostingConfiguration` in. + :param chc: The `ContentHostingConfiguration` to set in the provisioning session. + :return: ``True`` if the new `ContentHostingConfiguration` was successfully set in the provisioning session or ``False`` if + the operation failed (e.g. because there was already a `ContentHostingConfiguration` set). + ''' if provisioning_session not in self.__provisioning_sessions: return False await self.__connect() @@ -226,6 +335,13 @@ async def contentHostingConfigurationCreate(self, provisioning_session: Resource return True async def contentHostingConfigurationGet(self, provisioning_session: ResourceId) -> Optional[ContentHostingConfiguration]: + '''Retrieve the `ContentHostingConfiguration` set on a provisioning session + + :param provisioning_session: The provisioning session id to retrieve the `ContentHostingConfiguration` for. + + :return: a `ContentHostingConfiguration` for the provisioning session or ``None`` if the provisioning session does not + exist or if it has no `ContentHostingConfiguration` set. + ''' if provisioning_session not in self.__provisioning_sessions: return None await self.__cacheContentHostingConfiguration(provisioning_session) @@ -236,10 +352,27 @@ async def contentHostingConfigurationGet(self, provisioning_session: ResourceId) # Convenience methods - async def createDownlinkPullProvisioningSession(self, app_id, asp_id=None) -> Optional[ResourceId]: + async def createDownlinkPullProvisioningSession(self, app_id: ApplicationId, asp_id: Optional[ApplicationId] = None) -> Optional[ResourceId]: + '''Create a downlink provisioning session + + :param app_id: The mandatory external application id for the provisioning session. + :param asp_id: The optional ASP id for the provisioning session. + :return: the new provisioning session id or ``None`` if creation failed. + ''' return await self.provisioningSessionCreate(PROVISIONING_SESSION_TYPE_DOWNLINK, app_id, asp_id) async def createNewCertificate(self, provisioning_session: ResourceId, domain_name_alias: Optional[str] = None) -> Optional[ResourceId]: + '''Create a new certificate + + This will create a new certificate for the provisioning session. If *domain_name_alias* is not given this will leave + creation of the certificate up to the M1 server (5GMS Application Function). If *domain_name_alias* is given and is not + ``None`` then this will reserve a certificate for the provisioning session, sign the CSR using the local `CertificateSigner` + object and set the signed public certificate for the provisioning session. + + :param provisioning_session: The provisioning session id of the provisioning session to create the certificate in. + :param domain_name_alias: An optional ``domainNameAlias`` to add to the certificate. + :return: The certificate id of the newly created certificate or ``None`` if the certificate could not be created. + ''' # simple case just create the certificate if domain_name_alias is None or len(domain_name_alias) == 0: return await self.certificateCreate(provisioning_session) @@ -257,7 +390,37 @@ async def createNewCertificate(self, provisioning_session: ResourceId, domain_na return None return cert_id - async def createNewDownlinkPullStream(self, ingesturl, entrypoint, app_id, name=None, asp_id=None, ssl=False, insecure=True, domain_name_alias=None): + async def createNewDownlinkPullStream(self, ingesturl: str, app_id: ApplicationId, entrypoint: Optional[str] = None, name: Optional[str] = None, asp_id: Optional[ApplicationId] = None, ssl: bool = False, insecure: bool = True, domain_name_alias: Optional[str] = None) -> ResourceId: + '''Create a new downlink pull stream + + This will create a new provisioning session, reserve any necessary certificates (if *ssl* is requested) and set the + `ContentHostingConfiguration`. + + The provisioning session is created with the *app_id* and *asp_id* provided. + + If *ssl* is ``True`` then a certificate will be created in the new provisioning session. This certificate will use the + *domain_name_alias* if set. + + The `ContentHostingConfiguration` set in the new provisioning session is created from the *ingesturl*, *entrypoint* and + *name* and will contain a ``distributionConfiguration`` for an HTTP distribution if *insecure* is ``True`` (the default) + and an HTTPS distribution, using the new certificate, if *ssl* is ``True`` (default is no HTTPS). + + :param ingesturl: The ingest URL for the `ContentHostingConfiguration` to create. + :param app_id: The external application id for creatation of the provisioning session. + :param entrypoint: Optional ``entryPointPath`` for the `ContentHostingConfiguration`. + :param name: Optional ``name`` for the `ContentHostingConfiguration`. + :param asp_id: Optional Application Service Provider Id for creating the provisioning session. + :param ssl: If ``True`` include an HTTPS ``distributionConfiguration`` in the `ContentHostingConfiguration`. + :param insecure: If ``True`` include an HTTP ``distributionConfiguration`` in the `ContentHostingConfiguration`. + :param domain_name_alias: Optional ``domainNameAlias`` to include in the ``distributionConfiguration`` in the + `ContentHostingConfiguration`. + + :return: The provisioning session id + :raise RuntimeError: if the creation of provisioning session, certificate or content hosting configuration fails. + ''' + # Abort if bad parameters + if not ssl and not insecure: + raise RuntimeError('Cannot create a stream without HTTP and HTTPS distributions.') # Create a new provisioning session provisioning_session: ResourceId = await self.provisioningSessionCreate(PROVISIONING_SESSION_TYPE_DOWNLINK, app_id, asp_id) if provisioning_session is None: @@ -297,11 +460,19 @@ async def createNewDownlinkPullStream(self, ingesturl, entrypoint, app_id, name= chc['entryPointPath'] = entrypoint if not await self.contentHostingConfigurationCreate(provisioning_session, chc): raise RuntimeError('Failed to create the content hosting configuration') - return True + return provisioning_session # Private methods - async def __reloadFromDataStore(self): + async def __reloadFromDataStore(self) -> None: + '''Reload persistent information from the DataStore + + Checks the provisioning session ids retrieved from the DataStore against the M1 server and will delete any that are no + longer available. + + :meta private: + :return: None + ''' if self.__data_store_dir is None: return @@ -327,18 +498,35 @@ async def __reloadFromDataStore(self): self.__provisioning_sessions[prov_sess] = None async def __getProvisioningSessionCache(self, provisioning_session_id: ResourceId) -> Optional[dict]: + '''Find a provisioning session cache + + :meta private: + :param provisioning_session_id: The provisioning session id to get the cache for. + :return: The cache `dict` or ``None`` if the cache doesn't exist. + ''' if provisioning_session_id not in self.__provisioning_sessions: return None await self.__cacheProvisioningSession(provisioning_session_id) return self.__provisioning_sessions[provisioning_session_id] - async def __cacheResources(self): + async def __cacheResources(self) -> None: + '''Cache the provisioning session resources lists + + Caches the provisioning session information for each known provisioning session + ''' if len(self.__provisioning_sessions) == 0: return for prov_sess in self.__provisioning_sessions.keys(): self.__cacheProvisioningSession(prov_sess) - async def __cacheProvisioningSession(self, prov_sess: ResourceId): + async def __cacheProvisioningSession(self, prov_sess: ResourceId) -> None: + '''Cache the provisioning session resource lists for a provisioning session + + Will only cache if the old cache didn't exist or has expired. + + :meta private: + :param prov_sess: The id of provisioning session to cache. + ''' ps = self.__provisioning_sessions[prov_sess] now = datetime.datetime.now(datetime.timezone.utc) if ps is None or ps['cache-until'] is None or ps['cache-until'] < now: @@ -358,6 +546,13 @@ async def __cacheProvisioningSession(self, prov_sess: ResourceId): ps['certificates'] = {k: None for k in ps['provisioningsession']['serverCertificateIds']} async def __cacheProtocols(self, provisioning_session_id: ResourceId): + '''Cache the ContentProtocols for a provisioning session + + Will only cache if the old cache didn't exist or has expired. + + :meta private: + :param provisioning_session_id: The id of provisioning session to cache the `ContentProtocols` for. + ''' await self.__cacheProvisioningSession(provisioning_session_id) ps = self.__provisioning_sessions[provisioning_session_id] now = datetime.datetime.now(datetime.timezone.utc) @@ -368,6 +563,13 @@ async def __cacheProtocols(self, provisioning_session_id: ResourceId): ps['protocols'].update({k.lower(): v for k,v in result.items()}) async def __cacheCertificates(self, provisioning_session_id: ResourceId): + '''Cache all public certificates for the provisioning session + + Will only cache if the old cache didn't exist or has expired. + + :meta private: + :param provisioning_session_id: The id of provisioning session to cache the public certificates for. + ''' await self.__cacheProvisioningSession(provisioning_session_id) ps = self.__provisioning_sessions[provisioning_session_id] now = datetime.datetime.now(datetime.timezone.utc) @@ -391,7 +593,14 @@ async def __cacheCertificates(self, provisioning_session_id: ResourceId): if ret_err is not None: raise ret_err - async def __cacheContentHostingConfiguration(self, provisioning_session_id: ResourceId): + async def __cacheContentHostingConfiguration(self, provisioning_session_id: ResourceId) -> None: + '''Cache the `ContentHostingConfiguration` for a provisioning session + + Will only cache if the old cache didn't exist or has expired. + + :meta private: + :param provisioning_session_id: The id of provisioning session to cache the `ContentHostingConfiguration` for. + ''' await self.__cacheProvisioningSession(provisioning_session_id) ps = self.__provisioning_sessions[provisioning_session_id] now = datetime.datetime.now(datetime.timezone.utc) @@ -407,7 +616,15 @@ async def __cacheContentHostingConfiguration(self, provisioning_session_id: Reso else: ps['content-hosting-configuration'] = None - async def __getCertificateSigner(self): + async def __getCertificateSigner(self) -> CertificateSigner: + '''Get the `CertificateSigner` + + Creates the CertificateSigner object if we don't already have one. + + :meta private: + :return: a `CertificateSigner` + :raise RuntimeError: if the certificate signer requested is not derived from `CertificateSigner`. + ''' if self.__cert_signer is None: self.__cert_signer = 'rt_m1_client.certificates.DefaultCertificateSigner' if isinstance(self.__cert_signer, str): @@ -420,11 +637,17 @@ async def __getCertificateSigner(self): raise RuntimeError('The certificate signer class given is not derived from CertificateSigner') return self.__cert_signer - async def __connect(self): + async def __connect(self) -> None: + '''Connect to the M1Client + + :meta private: + ''' if self.__m1_client is None: self.__m1_client = M1Client(self.__m1_host) - def _dump_state(self): + def _dump_state(self) -> None: + '''Dump the current provisioning session cache to the log + ''' self.__log.debug(repr(self.__provisioning_sessions)) __all__ = [ diff --git a/tools/python3/lib/rt_m1_client/types.py b/tools/python3/lib/rt_m1_client/types.py index ade7a5c..358b85c 100644 --- a/tools/python3/lib/rt_m1_client/types.py +++ b/tools/python3/lib/rt_m1_client/types.py @@ -39,15 +39,27 @@ ProvisioningSessionType = Literal['DOWNLINK','UPLINK'] class ProvisioningSessionMandatory(TypedDict): + '''Madatory fields for a `ProvisioningSession` + ''' provisioningSessionId: ProvisioningSessionId provisioningSessionType: ProvisioningSessionType externalApplicationId: ApplicationId class ProvisioningSession (ProvisioningSessionMandatory, total=False): + '''A `ProvisioningSession` object as defined in TS 26.512 + ''' aspId: ApplicationId @staticmethod def fromJSON(json_str: str) -> "ProvisioningSession": + '''Create a `ProvisioningSession` from a JSON string + + :param str json_str: The JSON string to convert to a `ProvisioningSession`. + + :return: a `ProvisioningSession` holding the data from the *json_str*. + :rtype: ProvisioningSession + :raise TypeError: if there is a problem with interpretting the *json_str* as a `ProvisioningSession`. + ''' ret: dict = json.loads(json_str) for mandatory_field in ProvisioningSessionMandatory.__required_keys__: if mandatory_field not in ret: @@ -57,75 +69,90 @@ def fromJSON(json_str: str) -> "ProvisioningSession": return ProvisioningSession(ret) -PROVISIONING_SESSION_TYPE_DOWNLINK: ProvisioningSessionType = 'DOWNLINK' -PROVISIONING_SESSION_TYPE_UPLINK: ProvisioningSessionType = 'UPLINK' +PROVISIONING_SESSION_TYPE_DOWNLINK: ProvisioningSessionType = 'DOWNLINK' #: Downlink `ProvisioningSessionType`. +PROVISIONING_SESSION_TYPE_UPLINK: ProvisioningSessionType = 'UPLINK' #: Uplink `ProvisioningSessionType`. # TS 26.512 ContentHostingConfiguration class PathRewriteRule(TypedDict): '''PathRewriteRule structure in TS 26.512 ''' - requestPathPattern: str - mappedPath: str + requestPathPattern: str #: A regex to match the request path. + mappedPath: str #: The path to map in instead of the matched path. -class CachingDirectivesMandatory(TypedDict): +class CachingDirectiveMandatory(TypedDict): '''Mandatory fields from CachingConfiguration.cachingDirectives structure in TS 26.512 ''' - noCache: bool + noCache: bool #: ``True`` if ``no-cache`` should be included for this directive. -class CachingDirectives(CachingDirectivesMandatory, total=False): +class CachingDirective(CachingDirectiveMandatory, total=False): '''CachingConfiguration.cachingDirectives structure in TS 26.512 ''' - statusCodeFilters: List[int] - maxAge: int + statusCodeFilters: List[int] #: A list of status codes to apply this cache directive for. + maxAge: int #: A ``max-age`` to apply for this directive. class CachingConfigurationMandatory(TypedDict): '''Mandatory fields from CachingConfiguration structure in TS 26.512 ''' - urlPatternFilter: str + urlPatternFilter: str #: A URL pattern to match for the cache configuration class CachingConfiguration(CachingConfigurationMandatory, total=False): '''CachingConfiguration structure in TS 26.512 ''' - cachingDirectives: CachingDirectives + cachingDirectives: List[CachingDirective] #: Array of cache directives for the matched URL class ContentProtocolDescriptorMandatory(TypedDict): '''Mandatory fields from ContentProtocolDescriptor in TS 26.512 ''' - termIdentifier: Uri + termIdentifier: Uri #: A URI (usually URN) to identify an ingest protocol. class ContentProtocolDescriptor(ContentProtocolDescriptorMandatory, total=False): '''ContentProtocolDescriptor structure in TS 26.512 ''' - descriptionLocator: Uri + descriptionLocator: Uri #: A URL to documentation describing the *termIdentfier*. class ContentProtocols(TypedDict, total=False): '''ContentProtocols structure in TS 26.512 ''' - downlinkIngestProtocols: List[ContentProtocolDescriptor] - uplinkEgestProtocols: List[ContentProtocolDescriptor] - geoFencingLocatorTypes: List[Uri] + downlinkIngestProtocols: List[ContentProtocolDescriptor] #: An array of available downlink ingest protocols. + uplinkEgestProtocols: List[ContentProtocolDescriptor] #: An array of available uplink ingest protocols. + geoFencingLocatorTypes: List[Uri] #: An array of available geo-fencing location types. @staticmethod def fromJSON(json_str: str) -> "ContentProtocols": + '''Create a `ContentProtocols` from a JSON string + + :param str json_str: The JSON string to convert to a `ContentProtocols`. + :return: a `ContentProtocols` containing the data from the *json_str*. + :rtype: ContentProtocols + :raise TypeError: if the *json_str* could not be interpretted as a `ContentProtocols`. + ''' return ContentProtocols(json.loads(str)) class DistributionNetworkType(enum.Enum): '''Enumeration DistributionNetworkType in TS 26.512 ''' - NETWORK_EMBMS = enum.auto() + NETWORK_EMBMS = enum.auto() #: Distribution type is via EMBMS network. - def __str__(self): + def __str__(self) -> str: + '''String representation of the `DistributionNetworkType`. + + :return: a `str` containing the name of the enumerated `DistributionNetworkType`. + ''' return self.name class DistributionMode(enum.Enum): '''Enumeration DistributionMode in TS 26.512 ''' - MODE_EXCLUSIVE = enum.auto() - MODE_HYBRID = enum.auto() - MODE_DYNAMIC = enum.auto() + MODE_EXCLUSIVE = enum.auto() #: Distribution mode is exclusive + MODE_HYBRID = enum.auto() #: Distribution mode is hybrid + MODE_DYNAMIC = enum.auto() #: Distribution mode is dynamic def __str__(self): + '''String representation of the `DistributionMode`. + + :return: a `str` containing the name of the enumerated `DistributionMode`. + ''' return self.name class DistributionConfiguration(TypedDict, total=False): @@ -196,6 +223,11 @@ def fromJSON(chc_json: str) -> "ContentHostingConfiguration": @classmethod def format(cls, chc: "ContentHostingConfiguration") -> str: + '''Get a formatted `str` representation of a `ContentHostingConfiguration`. + + :param ContentHostingConfiguration chc: The `ContentHostingConfiguration` to format. + :return: a formatted `str` representation of the `ContentHostingConfiguration`. + ''' return f'''Name: {chc['name']} {cls.__formatEntryPoint(chc)}Ingest: Type: {chc['ingestConfiguration']['protocol']} @@ -206,6 +238,14 @@ def format(cls, chc: "ContentHostingConfiguration") -> str: @classmethod def __formatDistributions(cls, chc: "ContentHostingConfiguration", indent: int = 0) -> str: + '''Format a ContentHostingConfiguration.distributionConfigurations + + :meta private: + :param ContentHostingConfiguration chc: The `ContentHostingConfiguration` to get the distributionConfigurations from. + :param int indent: The amount of spaces to indent the formatted distributionConfigurations by. + + :return: a `str` containing the distributionConfigurations as formatted text. + ''' prefix = ' '*indent dists = [] for d in chc['distributionConfigurations']: @@ -255,6 +295,14 @@ def __formatDistributions(cls, chc: "ContentHostingConfiguration", indent: int = @classmethod def __formatEntryPoint(cls, chc: "ContentHostingConfiguration", indent: int = 0) -> str: + '''Format an ``entryPointPath`` as a string. + + :meta private: + :param ContentHostingConfiguration chc: The `ContentHostingConfiguration` to look for an ``entryPointPath`` in. + :param int indent: The amount of spaces to indent the formatted ``entryPointPath`` by. + + :return: the formatted ``entryPointPath`` if it exists or an empty string if it does not. + ''' if 'entryPointPath' not in chc: return '' prefix = ' '*indent @@ -354,11 +402,15 @@ class ProblemDetail(TypedDict, total=False): nrfId: str @staticmethod - def fromJSON(problem_detail_json: str): + def fromJSON(problem_detail_json: str) -> "ProblemDetail": ''' - Generate a ProblemDetail structure from a JSON string + Generate a `ProblemDetail` structure from a JSON string + + :param str problem_detail_json: The JSON string to convert to a `ProblemDetail`. + :return: a `ProblemDetail` containing the data from the *problem_detail_json* JSON string. ''' prob_detail = json.loads(problem_detail_json) + # Convert enumerated type strings to their enum values if 'accessTokenError' in prob_detail: for ate in prob_detail['accessTokenError']: ate['error'] = AccessTokenErrError(ate['error']) diff --git a/tools/python3/m1_session_cli.py b/tools/python3/m1_session_cli.py index e919d42..aa61b77 100755 --- a/tools/python3/m1_session_cli.py +++ b/tools/python3/m1_session_cli.py @@ -627,18 +627,18 @@ async def parse_args() -> Tuple[argparse.Namespace,Configuration]: help='PEM file to load the public certificate from, if omitted will use stdin instead') # m1-session-cli check-certificate-renewal - parser_checkrenewal = subparsers.add_parser('check-certificate-renewal', help='Renew all certificates if close to expiry') - parser_checkrenewal.set_defaults(command=cmd_check_all_renewal) + #parser_checkrenewal = subparsers.add_parser('check-certificate-renewal', help='Renew all certificates if close to expiry') + #parser_checkrenewal.set_defaults(command=cmd_check_all_renewal) # m1-session-cli renew-certificate -p # m1-session-cli renew-certificate [] - parser_renewcert = subparsers.add_parser('renew-certificate', help='Force renewal of a specific certificate') - parser_renewcert.set_defaults(command=cmd_renew_certs) - parser_renewcert_filter = parser_renewcert.add_mutually_exclusive_group(required=True) - parser_renewcert_filter.add_argument('-p', '--provisioning-session', help='Renew by provisioning session id') - parser_renewcert_filter.add_argument('ingesturl', metavar='ingest-URL', nargs='?', help='The ingest URL prefix to use') + #parser_renewcert = subparsers.add_parser('renew-certificate', help='Force renewal of a specific certificate') + #parser_renewcert.set_defaults(command=cmd_renew_certs) + #parser_renewcert_filter = parser_renewcert.add_mutually_exclusive_group(required=True) + #parser_renewcert_filter.add_argument('-p', '--provisioning-session', help='Renew by provisioning session id') + #parser_renewcert_filter.add_argument('ingesturl', metavar='ingest-URL', nargs='?', help='The ingest URL prefix to use') # The entry-point-path should go with ingest-URL, but argparser lacks the ability to do subgroups - parser_renewcert.add_argument('entrypoint', metavar='entry-point-path', nargs='?', help='The media player entry point suffix.') + #parser_renewcert.add_argument('entrypoint', metavar='entry-point-path', nargs='?', help='The media player entry point suffix.') args = parser.parse_args() @@ -687,6 +687,9 @@ async def main(): except M1Error as err: print(f'Communication error: {err}') return 2 + except Exception as err: + print(f'General failure: {err}') + return 2 return 0 def app(): From 2526d876f01e0e0fea8c1c19423b7fa5f436256a Mon Sep 17 00:00:00 2001 From: David Waring Date: Fri, 17 Mar 2023 17:26:13 +0000 Subject: [PATCH 35/48] Fix missing imports --- tools/python3/m1_client_cli.py | 264 ++++++++++++++++++++++++++++----- 1 file changed, 229 insertions(+), 35 deletions(-) diff --git a/tools/python3/m1_client_cli.py b/tools/python3/m1_client_cli.py index 3636b00..2ce029d 100755 --- a/tools/python3/m1_client_cli.py +++ b/tools/python3/m1_client_cli.py @@ -24,54 +24,248 @@ This provides a simple command line interface which can be used to manipulate the configuration of a 5GMS Application Function via the M1 interface. + +Syntax: + m1-client -h + m1-client provisioning create [-h] (-d|-u) [] + m1-client provisioning show [-h] + m1-client provisioning delete [-h] + m1-client protocols [-h] + m1-client certificates create [-h] [--csr] + m1-client certificates upload [-h] + m1-client certificates show [-h] [--info] + m1-client certificates delete [-h] + m1-client hosting create [-h] + m1-client hosting show [-h] + m1-client hosting update [-h] + m1-client hosting delete [-h] + m1-client hosting purge [-h] [] ''' +import argparse import asyncio import sys +from typing import Optional -from rt_m1_client import client as m1_client +from rt_m1_client.client import M1Client, ProvisioningSessionResponse, ContentProtocolsResponse, ServerCertificateSigningRequestResponse, ServerCertificateResponse from rt_m1_client.types import PROVISIONING_SESSION_TYPE_DOWNLINK from rt_m1_client.exceptions import M1Error +async def cmd_provisioning_create(args: argparse.Namespace) -> int: + client = await getClient(args) + asp_id = args.asp_id + app_id = args.external_app_id + if args.downlink: + prov_type = PROVISIONING_SESSION_TYPE_DOWNLINK + else: + prov_type = PROVISIONING_SESSION_TYPE_UPLINK + prov_sess_resp: Optional[ProvisioningSessionResponse] = await client.createProvisioningSession(prov_type, app_id, asp_id) + if prov_sess_resp is None: + print('Failed to create provisioning session') + return 1 + print(f"provisioning_session_id={prov_sess_resp['ProvisioningSessionId']}") + return 0 + +async def cmd_provisioning_show(args: argparse.Namespace) -> int: + client = await getClient(args) + provisioning_session_id = args.provisioning_session_id + prov_sess_resp: Optional[ProvisioningSessionResponse] = await client.getProvisioningSessionById(provisioning_session_id) + if prov_sess_resp is None: + print('Failed to fetch provisioning session') + return 1 + print(f"{prov_sess_resp['ProvisioningSession']!r}") + return 0 + +async def cmd_provisioning_delete(args: argparse.Namespace) -> int: + client = await getClient(args) + provisioning_session_id = args.provisioning_session_id + prov_sess_resp: bool = await client.destroyProvisioningSession(provisioning_session_id) + if not prov_sess_resp: + print('Failed to delete provisioning session') + return 1 + print('Provisioning session deleted') + return 0 + +async def cmd_protocols(args: argparse.Namespace) -> int: + client = await getClient(args) + provisioning_session_id = args.provisioning_session_id + resp: Optional[ContentProtocolsResponse] = await client.retrieveContentProtocols(provisioning_session_id) + if resp is None: + print('Failed to get ContentProtocols for provisioning session') + return 1 + print(f"{resp['ContentProtocols']!r}") + return 0 + +async def cmd_certificates_create(args: argparse.Namespace) -> int: + client = await getClient(args) + provisioning_session_id = args.provisioning_session_id + csr = args.csr + resp: Optional[ServerCertificateSigningRequestResponse] = await client.createOrReserveServerCertificate(provisioning_session_id, csr=csr) + if resp is None: + print('Failed to create a server certificate in the provisioning session') + return 1 + print(f"certificate_id={resp['ServerCertificateId']}") + if csr: + print(resp['CertificateSigningRequestPEM']) + return 0 + + +async def cmd_certificates_upload(args: argparse.Namespace) -> int: + client = await getClient(args) + provisioning_session_id = args.provisioning_session_id + certificate_id = args.certificate_id + pem_file = args.PEM_file + async with aiofiles.open(pem_file, mode='r') as in_file: + pem = await in_file.read() + resp: bool = await client.uploadServerCertificate(provisioning_session_id, certificate_id, pem) + if not resp: + print('Failed to upload public certificate') + return 1 + print('Public certificate uploaded') + return 0 + +async def cmd_certificates_show(args: argparse.Namespace) -> int: + client = await getClient(args) + provisioning_session_id = args.provisioning_session_id + certificate_id = args.certificate_id + info = args.info + resp: Optional[ServerCertificateResponse] = await client.retrieveServerCertificate(provisioning_session_id, certificate_id) + if resp is None: + print('Certificate pending upload') + return 1 + if info: + print(f'''certificate_id={resp['ServerCertificateId']} +** TODO: Use OpenSSL to print certificate details ** +''') + else: + print(resp['ServerCertificate']) + return 0 + +async def cmd_certificates_delete(args: argparse.Namespace) -> int: + raise NotImplementedError(__name__ + ' has not been implemented yet') + +async def cmd_hosting_create(args: argparse.Namespace) -> int: + raise NotImplementedError(__name__ + ' has not been implemented yet') + +async def cmd_hosting_show(args: argparse.Namespace) -> int: + raise NotImplementedError(__name__ + ' has not been implemented yet') + +async def cmd_hosting_update(args: argparse.Namespace) -> int: + raise NotImplementedError(__name__ + ' has not been implemented yet') + +async def cmd_hosting_delete(args: argparse.Namespace) -> int: + raise NotImplementedError(__name__ + ' has not been implemented yet') + +async def cmd_hosting_purge(args: argparse.Namespace) -> int: + raise NotImplementedError(__name__ + ' has not been implemented yet') + +async def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(prog='m1-client', description='M1 Client API tool') + subparsers = parser.add_subparsers(required=True) + + # Parent parser for AF address + parent_addr = argparse.ArgumentParser(add_help=False) + parent_addr.add_argument('address', metavar='address:port', help='Address of the 5GMS AF') + + # Parent parser for AF address and provisioning session id + parent_addr_prov = argparse.ArgumentParser(parents=[parent_addr], add_help=False) + parent_addr_prov.add_argument('provisioning-session-id', help='The provisioning session id') + + # m1-client provisioning ... + parser_provisioning = subparsers.add_parser('provisioning', help='Provisioning Session Management') + provisioning_subparsers = parser_provisioning.add_subparsers(required=True) + + # m1-client provisioning create [-h] (-d|-u) [] + parser_provisioning_create = provisioning_subparsers.add_parser('create', parents=[parent_addr], help='Create a new provisioning session') + parser_provisioning_create.set_defaults(command=cmd_provisioning_create) + parser_provisioning_create_type = parser_provisioning_create.add_mutually_exclusive_group(required=True) + parser_provisioning_create_type.add_argument('-d', '--downlink', help='Provisioning session is a downlink') + parser_provisioning_create_type.add_argument('-u', '--uplink', help='Provisioning session is an uplink') + parser_provisioning_create.add_argument('external-app-id', help='The external application id') + parser_provisioning_create.add_argument('asp-id', nargs='?', help='The Application Service Provider id') + + # m1-client provisioning show [-h] + parser_provisioning_show = provisioning_subparsers.add_parser('show', parents=[parent_addr_prov], help='Retreive and display a provisioning session') + parser_provisioning_show.set_defaults(command=cmd_provisioning_show) + + # m1-client provisioning delete [-h] + parser_provisioning_delete = provisioning_subparsers.add_parser('delete', parents=[parent_addr_prov], help='Delete a provisioning session') + parser_provisioning_delete.set_defaults(command=cmd_provisioning_delete) + + # m1-client protocols [-h] + parser_protocols = subparsers.add_parser('protocols', parents=[parent_addr_prov], help='Get the ContentProtocols for a provisioning session') + parser_protocols.set_defaults(command=cmd_protocols) + + # m1-client certificates ... + parser_certificates = subparsers.add_parser('certificates', help='ServerCertificatesProvisioning API') + certificates_subparsers = parser_certificates.add_subparsers(required=True) + + # m1-client certificates create [-h] [--csr] + parser_certificates_create = certificates_subparsers.add_parser('create', parents=[parent_addr_prov], help='Create or reserve a new certificate') + parser_certificates_create.set_defaults(command=cmd_certificates_create) + parser_certificates_create.add_argument('--csr', action='store_true', help='Reserve a certificate and return the CSR') + + # m1-client certificates upload [-h] + parser_certificates_upload = certificates_subparsers.add_parser('upload', parents=[parent_addr_prov], help='Upload a public certificate') + parser_certificates_upload.set_defaults(command=cmd_certificates_upload) + parser_certificates_upload.add_argument('certificate-id', help='The certificate id to upload') + parser_certificates_upload.add_argument('PEM-file', help='The public certificate PEM file to upload') + + # m1-client certificates show [-h] [--info] + parser_certificates_show = certificates_subparsers.add_parser('show', parents=[parent_addr_prov], help='Display a public certificate') + parser_certificates_show.add_argument('certificate-id', help='The certificate id to upload') + parser_certificates_show.add_argument('-i', '--info', action='store_true', help='Display certificate information instead of the PEM data') + + # m1-client certificates delete [-h] + parser_certificates_delete = certificates_subparsers.add_parser('delete', parents=[parent_addr_prov], help='Delete a certificate') + parser_certificates_show.add_argument('certificate-id', help='The certificate id to delete') + + # m1-client hosting ... + parser_hosting = subparsers.add_parser('hosting', help='ContentHostingProvisioing APIs') + hosting_subparsers = parser_hosting.add_subparsers(required=True) + + # m1-client hosting create [-h] + parser_hosting_create = hosting_subparsers.add_parser('create', parents=[parent_addr_prov], help='Add a ContentHostingConfiguration to a provisioning session') + parser_hosting_create.set_defaults(command=cmd_hosting_create) + parser_hosting_create.add_argument('CHC-JSON-file', help='Path to a ContentHostingConfiguration JSON file') + + # m1-client hosting show [-h] + parser_hosting_show = hosting_subparsers.add_parser('show', parents=[parent_addr_prov], help='Display the ContentHostingConfiguration for a provisioning session') + parser_hosting_show.set_defaults(command=cmd_hosting_show) + + # m1-client hosting update [-h] + parser_hosting_update = hosting_subparsers.add_parser('update', parents=[parent_addr_prov], help='Update the existing ContentHostingConfiguration in a provisioning session') + parser_hosting_update.set_defaults(command=cmd_hosting_update) + parser_hosting_update.add_argument('CHC-JSON-file', help='Path to a ContentHostingConfiguration JSON file') + + # m1-client hosting delete [-h] + parser_hosting_delete = hosting_subparsers.add_parser('delete', parents=[parent_addr_prov], help='Delete the ContentHostingConfiguration for a provisioning session') + parser_hosting_delete.set_defaults(command=cmd_hosting_delete) + + # m1-client hosting purge [-h] [] + parser_hosting_purge = hosting_subparsers.add_parser('purge', parents=[parent_addr_prov], help='Purge the cache for a provisioning session') + parser_hosting_purge.set_defaults(command=cmd_hosting_purge) + parser_hosting_purge.add_argument('path-regex', nargs='?', help='Regular expression to match for entries to purge') + + return parser.parse_args() + +async def getClient(args: argparse.Namespace) -> M1Client: + if not hasattr(args, 'address'): + raise RuntimeError('Attempt to connect to M1Client without an address') + (addr,port) = args.address.split(':') + port = int(port) + return M1Client((addr,port)) + async def main(): ''' Async application entry point ''' try: - m1_session = m1_client.M1Client(('127.0.0.22', 7778)) - provisioning_session_response = await m1_session.createProvisioningSession( - PROVISIONING_SESSION_TYPE_DOWNLINK, 'myAppId', 'myAspId') - if provisioning_session_response is None: - print('Failed to create a provisioning session!') - return 1 - - provisioning_session_id = provisioning_session_response['ProvisioningSessionId'] - print(f'Provisioning Session {provisioning_session_id} created') - - certificate_resp = await m1_session.createServerCertificate(provisioning_session_id) - if certificate_resp is None: - print('Failed to create a server certificate') - return 1 - - certificate_id = certificate_resp['ServerCertificateId'] - print(f'Created certificate {certificate_id}') - - chc = { - 'name': 'Test CHC', - 'entryPointPath': 'BigBuckBunny_4s_onDemand_2014_05_09.mpd', - 'ingestConfiguration': { - 'pull': True, - 'protocol': 'urn:3gpp:5gms:content-protocol:http-pull-ingest', - 'baseURL': 'https://ftp.itec.aau.at/datasets/DASHDataset2014/BigBuckBunny/4sec/', - }, - 'distributionConfigurations': [ - { - 'certificateId': certificate_id, - } - ] - } - result = await m1_session.createContentHostingConfiguration(provisioning_session_id, chc) - print(f'Created CHC: {repr(result)}') + args = await parse_args() + if hasattr(args, 'command'): + return await args.command(args) + print('Command not understood') + return 1 except M1Error as err: print(f'Communication error: {err}') return 2 From 2410690cd7159316869a9e4300a7deae21e0c97e Mon Sep 17 00:00:00 2001 From: David Waring Date: Fri, 17 Mar 2023 17:26:39 +0000 Subject: [PATCH 36/48] Drop m1-client from installation for now --- tools/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/meson.build b/tools/meson.build index 6a7e0d9..f52fe3d 100644 --- a/tools/meson.build +++ b/tools/meson.build @@ -4,7 +4,7 @@ fs = import('fs') support_scripts_dir = get_option('libexecdir') / 'rt-5gms' scripts = { -'python3/m1_client_cli.py': 'm1-client', +#'python3/m1_client_cli.py': 'm1-client', 'python3/m1_session_cli.py': 'm1-session' } From 31050c0108bd984d0b77a37880e2149bd5957835 Mon Sep 17 00:00:00 2001 From: David Waring Date: Mon, 20 Mar 2023 11:24:16 +0000 Subject: [PATCH 37/48] Point to the configuration wiki page in the top level README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1508093..5ada4d2 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,8 @@ specify an alternative configuration file. For example: The source example configuration file can be found in `~/rt-5gms-application-function/src/5gmsaf/msaf.yaml`. +Also see the [Configuring the Application Function](https://github.com/5G-MAG/rt-5gms-application-function/wiki/Configuring-the-Application-Function) wiki page for details on configuration. + ## Testing See the section on [Testing](https://github.com/5G-MAG/rt-5gms-application-function/wiki/Developing-and-Contributing#testing) in the wiki. From 2783c0e23418b5077e92a54f641b0af4bc8090ee Mon Sep 17 00:00:00 2001 From: deva Date: Mon, 20 Mar 2023 17:29:43 +0000 Subject: [PATCH 38/48] Modified to return correct Server header in response for the creation of contentHostingConfiguration --- src/5gmsaf/msaf-m1-sm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/5gmsaf/msaf-m1-sm.c b/src/5gmsaf/msaf-m1-sm.c index 3ea0eff..4ca22fa 100644 --- a/src/5gmsaf/msaf-m1-sm.c +++ b/src/5gmsaf/msaf-m1-sm.c @@ -268,7 +268,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) if (chc != NULL) { char *text; msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); - response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, NULL, m1_contentprotocolsdiscovery_api, app_meta); + response = nf_server_new_response(request->h.uri, "application/json", msaf_provisioning_session->contentHostingConfigurationReceived, msaf_provisioning_session->contentHostingConfigurationHash, msaf_self()->config.server_response_cache_control->m1_content_hosting_configurations_response_max_age, NULL, m1_contenthostingprovisioning_api, app_meta); text = cJSON_Print(chc); nf_server_populate_response(response, strlen(text), text, 201); ogs_assert(response); From 25d749188d8435fe19557c134523e2bdf75780ad Mon Sep 17 00:00:00 2001 From: David Waring Date: Mon, 20 Mar 2023 17:34:11 +0000 Subject: [PATCH 39/48] Add new separated interfaces to default msaf.yaml --- src/5gmsaf/msaf.yaml.in | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/5gmsaf/msaf.yaml.in b/src/5gmsaf/msaf.yaml.in index 6ec457c..054a607 100644 --- a/src/5gmsaf/msaf.yaml.in +++ b/src/5gmsaf/msaf.yaml.in @@ -135,6 +135,15 @@ msaf: sbi: - addr: 127.0.0.22 port: 7777 + m1: + - addr: 127.0.0.23 + port: 7777 + m5: + - addr: 127.0.0.24 + port: 7777 + maf: + - addr: 127.0.0.25 + port: 7777 applicationServers: - canonicalHostname: localhost urlPathPrefixFormat: /m4d/provisioning-session-{provisioningSessionId}/ From e6a42704267a25a4484b7eec733dd339e45fe6be Mon Sep 17 00:00:00 2001 From: David Waring Date: Tue, 21 Mar 2023 16:15:50 +0000 Subject: [PATCH 40/48] Fix issue with pull stream arguments. --- tools/python3/m1_session_cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/python3/m1_session_cli.py b/tools/python3/m1_session_cli.py index aa61b77..dfe32db 100755 --- a/tools/python3/m1_session_cli.py +++ b/tools/python3/m1_session_cli.py @@ -408,7 +408,7 @@ async def cmd_new_stream(args: argparse.Namespace, config: Configuration) -> int app_id = args.app_id or config.get('external_app_id') asp_id = args.asp_id or config.get('asp_id') domain_name_alias = args.domain_name_alias - provisioning_session_id = await session.createNewDownlinkPullStream(args.ingesturl, args.entrypoint, name=name, ssl=use_ssl, insecure=use_plain, app_id=app_id, asp_id=asp_id, domain_name_alias=domain_name_alias) + provisioning_session_id = await session.createNewDownlinkPullStream(args.ingesturl, app_id, args.entrypoint, name=name, ssl=use_ssl, insecure=use_plain, asp_id=asp_id, domain_name_alias=domain_name_alias) print(f'Hosting created as provisioning session {provisioning_session_id}') return 0 From ef150a4e42139a42a16d761f2fb2e9e9f48abef4 Mon Sep 17 00:00:00 2001 From: David Waring Date: Wed, 22 Mar 2023 14:28:02 +0000 Subject: [PATCH 41/48] Better path elements checking for M1 interface. --- src/5gmsaf/msaf-m1-sm.c | 47 +++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/src/5gmsaf/msaf-m1-sm.c b/src/5gmsaf/msaf-m1-sm.c index 4ca22fa..a329c3a 100644 --- a/src/5gmsaf/msaf-m1-sm.c +++ b/src/5gmsaf/msaf-m1-sm.c @@ -128,13 +128,21 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_sbi_message_free(&message); break; } - SWITCH(message.h.resource.component[0]) + if (!message.h.resource.component[0]) { + char *error; + error = ogs_strdup("Protocol on M1 requires a resource"); + ogs_error("%s", error); + ogs_assert(true == nf_server_send_error(stream, 404, 1, NULL, "No resource given", error, NULL, NULL, app_meta)); + ogs_sbi_message_free(&message); + break; + } + SWITCH(message.h.resource.component[0]) CASE("provisioning-sessions") SWITCH(message.h.method) CASE(OGS_SBI_HTTP_METHOD_POST) - if (message.h.resource.component[1] && message.h.resource.component[2] && message.h.resource.component[3]) { + if (message.h.resource.component[1] && message.h.resource.component[2] && message.h.resource.component[3] && !message.h.resource.component[4]) { msaf_provisioning_session_t *msaf_provisioning_session; if (!strcmp(message.h.resource.component[2],"content-hosting-configuration") && !strcmp(message.h.resource.component[3],"purge")) { @@ -220,7 +228,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } - } else if (message.h.resource.component[1] && message.h.resource.component[2]) { + } else if (message.h.resource.component[1] && message.h.resource.component[2] && !message.h.resource.component[3]) { msaf_provisioning_session_t *msaf_provisioning_session; if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); @@ -396,7 +404,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } } - } else if (message.h.resource.component[1]){ + } else if (message.h.resource.component[1] && !message.h.resource.component[2]){ msaf_provisioning_session_t *msaf_provisioning_session; msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); if(msaf_provisioning_session) { @@ -492,7 +500,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) break; CASE(OGS_SBI_HTTP_METHOD_GET) - if (message.h.resource.component[1] && message.h.resource.component[2] && message.h.resource.component[3]) { + if (message.h.resource.component[1] && message.h.resource.component[2] && message.h.resource.component[3] && !message.h.resource.component[4]) { if (!strcmp(message.h.resource.component[2],"certificates") ) { msaf_provisioning_session_t *msaf_provisioning_session; msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); @@ -555,7 +563,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exists.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } } - } else if (message.h.resource.component[1] && message.h.resource.component[2]) { + } else if (message.h.resource.component[1] && message.h.resource.component[2] && !message.h.resource.component[3]) { msaf_provisioning_session_t *msaf_provisioning_session; msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { @@ -603,7 +611,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Provisioning session does not exist.", err, NULL, m1_contentprotocolsdiscovery_api, app_meta)); } } - } else if (message.h.resource.component[1]) { + } else if (message.h.resource.component[1] && !message.h.resource.component[2]) { msaf_provisioning_session_t *msaf_provisioning_session = NULL; cJSON *provisioning_session = NULL; @@ -641,7 +649,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); if(msaf_provisioning_session) { ogs_info("PUT: with msaf_provisioning_session: %s", message.h.resource.component[1]); - if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { + if (!strcmp(message.h.resource.component[2],"content-hosting-configuration") && !message.h.resource.component[3]) { // process the POST body cJSON *entry; @@ -696,7 +704,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_assert(true == nf_server_send_error(stream, 404, 2, &message, "Failed to update the contentHostingConfiguration.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); } } - if (message.h.resource.component[1] && !strcmp(message.h.resource.component[2],"certificates") && message.h.resource.component[3]) { + if (!strcmp(message.h.resource.component[2],"certificates") && message.h.resource.component[3] && !message.h.resource.component[4]) { char *cert_id; char *cert; int rv; @@ -772,8 +780,12 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_free(cert); } + } else { + char *err = NULL; + asprintf(&err,"[%s]: Resource not found.", message.h.method); + ogs_error("%s", err); + ogs_assert(true == nf_server_send_error(stream, 404, 1, &message, "Resource not found.", err, NULL, m1_provisioningsession_api, app_meta)); } - } else { char *err = NULL; asprintf(&err,"Provisioning Session [%s] does not exist.", message.h.resource.component[1]); @@ -792,7 +804,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) CASE(OGS_SBI_HTTP_METHOD_DELETE) - if (message.h.resource.component[1] && !strcmp(message.h.resource.component[2],"certificates") && message.h.resource.component[3]) { + if (message.h.resource.component[1] && message.h.resource.component[2] && !strcmp(message.h.resource.component[2],"certificates") && message.h.resource.component[3] && !message.h.resource.component[4]) { ogs_sbi_response_t *response; msaf_provisioning_session_t *provisioning_session = NULL; provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); @@ -828,7 +840,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_assert(true == nf_server_send_error(stream, 404, 3, &message, "Provisioning session does not exist.", err, NULL, m1_servercertificatesprovisioning_api, app_meta)); } - } else if (message.h.resource.component[1] && message.h.resource.component[2]) { + } else if (message.h.resource.component[1] && message.h.resource.component[2] && !message.h.resource.component[3]) { msaf_provisioning_session_t *msaf_provisioning_session; ogs_sbi_response_t *response; if (!strcmp(message.h.resource.component[2],"content-hosting-configuration")) { @@ -858,7 +870,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) } - } else if (message.h.resource.component[1]) { + } else if (message.h.resource.component[1] && !message.h.resource.component[2]) { ogs_sbi_response_t *response; msaf_provisioning_session_t *provisioning_session = NULL; provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); @@ -1023,6 +1035,15 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_sbi_message_free(&message); break; } + if (!message.h.resource.component[0]) { + char *error; + error = ogs_strdup("Resource required for Management interface"); + ogs_error("%s", error); + ogs_assert(true == nf_server_send_error(stream, 404, 1, NULL, "Resource name required", error, NULL, maf_management_api, app_meta)); + ogs_sbi_message_free(&message); + break; + } + SWITCH(message.h.resource.component[0]) CASE("provisioning-sessions") From a45e8e500450dda1bc1586f68af5ce889201428e Mon Sep 17 00:00:00 2001 From: David Waring Date: Wed, 22 Mar 2023 15:00:31 +0000 Subject: [PATCH 42/48] Various fixes for bugs found in testing. --- .../python3/lib/rt_m1_client/certificates.py | 28 +++++----- tools/python3/lib/rt_m1_client/client.py | 4 +- tools/python3/lib/rt_m1_client/session.py | 23 +++++++- tools/python3/lib/rt_m1_client/types.py | 2 +- tools/python3/m1_session_cli.py | 55 ++++++++++++++++++- 5 files changed, 90 insertions(+), 22 deletions(-) diff --git a/tools/python3/lib/rt_m1_client/certificates.py b/tools/python3/lib/rt_m1_client/certificates.py index 00b8b17..cf566fd 100644 --- a/tools/python3/lib/rt_m1_client/certificates.py +++ b/tools/python3/lib/rt_m1_client/certificates.py @@ -109,33 +109,35 @@ async def signCertificate(self, csr: str, *args, domain_name_alias: Optional[str :return: a public X509 certificate in PEM format. ''' x509req: OpenSSL.crypto.X509Req = OpenSSL.crypto.load_certificate_request(OpenSSL.crypto.FILETYPE_PEM, csr.encode('utf-8')) - need_canonical_sans = True - for ext in x509req.get_extensions(): - ext_name = ext.get_short_name().decode('utf-8') - if ext_name == 'subjectAltName' and str(ext) == 'DNS:'+x509req.get_subject().commonName: - need_canonical_sans = False - sans: List[OpenSSL.crypto.X509Extension] = [] - if need_canonical_sans: - sans += [OpenSSL.crypto.X509Extension(b'subjectAltName', False, b'DNS:'+x509req.get_subject().commonName)] + # Adjust SANs + sans: List[bytes] = [] if domain_name_alias is not None: - sans += [OpenSSL.crypto.X509Extension(b'subjectAltName', False, b'DNS:'+domain_name_alias.encode('utf-8'))] - x509req.add_extensions(sans) + sans += [b'DNS:'+domain_name_alias.encode('utf-8')] + sans += [b'DNS:'+x509req.get_subject().commonName.encode('utf-8')] # Get local CA ca_key, ca = await self.__getLocalCA() # Convert CSR to X509 certificate x509 = OpenSSL.crypto.X509() - x509.set_subject(x509req.get_subject()) + if domain_name_alias is not None: + new_subj = x509.get_subject() + new_subj.commonName = domain_name_alias + new_subj.organizationName = '5G-MAG' + else: + x509.set_subject(x509req.get_subject()) x509.set_serial_number(1) x509.gmtime_adj_notBefore(0) x509.gmtime_adj_notAfter(self.__local_cert_days * 24 * 60 * 60) x509.set_issuer(ca.get_subject()) x509.set_pubkey(x509req.get_pubkey()) + # Copy any extensions we aren't replacing for ext in x509req.get_extensions(): - if ext.get_short_name() != b'authorityKeyIdentifier' and ext.get_short_name() != b'basicConstraints': + if ext.get_short_name() not in [b'subjectKeyIdentifier', b'authorityKeyIdentifier', b'basicConstraints', b'subjectAltName']: x509.add_extensions([ext]) x509.add_extensions([ + OpenSSL.crypto.X509Extension(b'subjectKeyIdentifier', False, b'hash', subject=x509), OpenSSL.crypto.X509Extension(b'authorityKeyIdentifier', False, b'keyid, issuer', issuer=ca), - OpenSSL.crypto.X509Extension(b'basicConstraints', True, b'CA:FALSE') + OpenSSL.crypto.X509Extension(b'basicConstraints', True, b'CA:FALSE'), + OpenSSL.crypto.X509Extension(b'subjectAltName', False, b','.join(sans)) ]) x509.sign(ca_key, "sha256") return OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, x509).decode('utf-8') diff --git a/tools/python3/lib/rt_m1_client/client.py b/tools/python3/lib/rt_m1_client/client.py index 2002e82..14fac43 100644 --- a/tools/python3/lib/rt_m1_client/client.py +++ b/tools/python3/lib/rt_m1_client/client.py @@ -170,7 +170,7 @@ async def destroyProvisioningSession(self, provisioning_session_id: ResourceId) :param ResourceId provisioning_session_id: The provisioning session to find. - :return: True if a provisioning session was deleted or False if there was no action. + :return: True if a provisioning session was deleted (or pending deletion) or False if there was no action. :raise M1ClientError: if there was a problem with the request :raise M1ServerError: if there was a server side issue preventing the creation of the provisioning session. @@ -178,7 +178,7 @@ async def destroyProvisioningSession(self, provisioning_session_id: ResourceId) result = await self.__do_request('DELETE', '/provisioning-sessions/' + provisioning_session_id, '', 'application/json') - if result['status_code'] == 204: + if result['status_code'] == 204 or result['status_code'] == 202: return True self.__default_response(result) return False diff --git a/tools/python3/lib/rt_m1_client/session.py b/tools/python3/lib/rt_m1_client/session.py index bfa136e..255a818 100644 --- a/tools/python3/lib/rt_m1_client/session.py +++ b/tools/python3/lib/rt_m1_client/session.py @@ -153,7 +153,7 @@ async def provisioningSessionDestroy(self, provisioning_session_id: ResourceId) if provisioning_session_id not in self.__provisioning_sessions: return None await self.__connect() - result = await self.__m1_client.destroyProvisioningSession(prov_sess) + result = await self.__m1_client.destroyProvisioningSession(provisioning_session_id) if result: del self.__provisioning_sessions[provisioning_session_id] if self.__data_store_dir: @@ -189,6 +189,19 @@ async def provisioningSessionCreate(self, prov_type: ProvisioningSessionType, ap await self.__data_store_dir.set('provisioning_sessions', list(self.__provisioning_sessions.keys())) return ps_id + async def provisioningSessionIdByIngestUrl(self, ingesturl: str, entrypoint: Optional[str] = None) -> Optional[ResourceId]: + ret = None + for ps_id in self.__provisioning_sessions.keys(): + await self.__cacheContentHostingConfiguration(ps_id) + ps = await self.__getProvisioningSessionCache(ps_id) + if ps is None or ps['content-hosting-configuration'] is None: + continue + if ps['content-hosting-configuration']['contenthostingconfiguration']['ingestConfiguration']['baseURL'] == ingesturl: + if (entrypoint is None and 'entryPointPath' not in ps['content-hosting-configuration']['contenthostingconfiguration']) or (entrypoint is not None and 'entryPointPath' in ps['content-hosting-configuration']['contenthostingconfiguration'] and ps['content-hosting-configuration']['contenthostingconfiguration']['entryPointPath'] == entrypoint): + ret = ps_id + break + return ret + # Certificates management async def certificateIds(self, provisioning_session_id: ResourceId) -> Optional[List[ResourceId]]: @@ -374,7 +387,9 @@ async def createNewCertificate(self, provisioning_session: ResourceId, domain_na :return: The certificate id of the newly created certificate or ``None`` if the certificate could not be created. ''' # simple case just create the certificate - if domain_name_alias is None or len(domain_name_alias) == 0: + if domain_name_alias is not None and len(domain_name_alias) == 0: + domain_name_alias = None + if domain_name_alias is None: return await self.certificateCreate(provisioning_session) # When domainNameAlias is used we need to use a CSR csr: Optional[Tuple[ResourceId,str]] = await self.certificateNewSigningRequest(provisioning_session) @@ -558,8 +573,10 @@ async def __cacheProtocols(self, provisioning_session_id: ResourceId): now = datetime.datetime.now(datetime.timezone.utc) if ps['protocols'] is None or ps['protocols']['cache-until'] is None or ps['protocols']['cache-until'] < now: await self.__connect() - result = await self.__m1_client.getContentProtocols(provisioning_session_id) + result = await self.__m1_client.retrieveContentProtocols(provisioning_session_id) if result is not None: + if ps['protocols'] is None: + ps['protocols'] = {} ps['protocols'].update({k.lower(): v for k,v in result.items()}) async def __cacheCertificates(self, provisioning_session_id: ResourceId): diff --git a/tools/python3/lib/rt_m1_client/types.py b/tools/python3/lib/rt_m1_client/types.py index 358b85c..bf361d1 100644 --- a/tools/python3/lib/rt_m1_client/types.py +++ b/tools/python3/lib/rt_m1_client/types.py @@ -127,7 +127,7 @@ def fromJSON(json_str: str) -> "ContentProtocols": :rtype: ContentProtocols :raise TypeError: if the *json_str* could not be interpretted as a `ContentProtocols`. ''' - return ContentProtocols(json.loads(str)) + return ContentProtocols(json.loads(json_str)) class DistributionNetworkType(enum.Enum): '''Enumeration DistributionNetworkType in TS 26.512 diff --git a/tools/python3/m1_session_cli.py b/tools/python3/m1_session_cli.py index dfe32db..134fb54 100755 --- a/tools/python3/m1_session_cli.py +++ b/tools/python3/m1_session_cli.py @@ -87,6 +87,7 @@ import os import os.path import sys +import traceback from typing import Tuple, List import json @@ -302,6 +303,7 @@ async def __prettyPrintCertificate(cert: str, indent: int = 0) -> None: end = datetime.datetime.strptime(end_str, '%Y%m%d%H%M%SZ').replace(tzinfo=datetime.timezone.utc) subject_key = None issuer_key = None + sans = [] for ext_num in range(x509.get_extension_count()): ext = x509.get_extension(ext_num) ext_name = ext.get_short_name().decode('utf-8') @@ -309,6 +311,8 @@ async def __prettyPrintCertificate(cert: str, indent: int = 0) -> None: subject_key = str(ext) elif ext_name == "authorityKeyIdentifier": issuer_key = str(ext) + elif ext_name == "subjectAltName": + sans += [s.strip() for s in str(ext).split(',')] cert_info_prefix=' '*indent cert_desc=f'{cert_info_prefix}Serial = {serial}\n{cert_info_prefix}Not before = {start}\n{cert_info_prefix}Not after = {end}\n{cert_info_prefix}Subject = {__formatX509Name(subject)}\n' if subject_key is not None: @@ -316,6 +320,9 @@ async def __prettyPrintCertificate(cert: str, indent: int = 0) -> None: cert_desc += f'{cert_info_prefix}Issuer = {__formatX509Name(issuer)}' if issuer_key is not None: cert_desc += f'\n{cert_info_prefix} key={issuer_key}' + if len(sans) > 0: + cert_desc += f'\n{cert_info_prefix}Subject Alternative Names:' + cert_desc += ''.join([f'\n{cert_info_prefix} {san}' for san in sans]) print(f'{cert_desc}') async def cmd_list_verbose(args: argparse.Namespace, config: Configuration) -> int: @@ -423,11 +430,46 @@ async def cmd_delete_stream(args: argparse.Namespace, config: Configuration) -> if args.provisioning_session is not None: ps_id = args.provisioning_session else: - ps_id = await session.provisioningSessionIdByIngestUrl(args.ingesturl, args.entrypointsuffix) + ps_id = await session.provisioningSessionIdByIngestUrl(args.ingesturl, args.entrypoint) if ps_id is None: print('No such hosting session found') return 1 - await session.provisioningSessionDestroy(ps_id) + result = await session.provisioningSessionDestroy(ps_id) + if result is None: + print(f'Provisioning Session {ps_id} not found') + return 1 + if not result: + print(f'Failed to destroy Provisioning Session {ps_id}') + return 1 + print(f'Provisioning Session {ps_id} and all its resources were destroyed') + return 0 + +async def cmd_protocols(args: argparse.Namespace, config: Configuration) -> int: + '''Perform ``protocols`` operation + + This will list the download and upload protocols for the provisioning session. + ''' + session = await get_session(config) + result = await session.provisioningSessionProtocols(args.provisioning_session) + if result is None: + print(f'Failed to fetch the content protocols for provisioning session {args.provisioning_session}') + return 1 + print(f'Protocols for {args.provisioning_session}:') + if 'downlinkIngestProtocols' in result: + print(' Downlink:') + print('\n'.join([f' {proto["termIdentifier"]}' for proto in result['downlinkIngestProtocols']])) + else: + print(' No downlink capability') + if 'uplinkEgestProtocols' in result: + print(' Uplink:') + print('\n'.join([f' {proto["termIdentifier"]}' for proto in result['uplinkEgestProtocols']])) + else: + print(' No uplink capability') + if 'geoFencingLocatorTypes' in result: + print(' Geo-fencing:') + print('\n'.join([f' {proto}' for proto in result['geoFencingLocatorTypes']])) + else: + print(' No geo-fencing capability') return 0 async def cmd_new_certificate(args: argparse.Namespace, config: Configuration) -> int: @@ -531,7 +573,7 @@ async def parse_args() -> Tuple[argparse.Namespace,Configuration]: ''' cfg = Configuration() - parser = argparse.ArgumentParser(prog='m1-session-cli', description='M1 Session Tool') + parser = argparse.ArgumentParser(prog='m1-session', description='M1 Session Tool') subparsers = parser.add_subparsers(required=True) # m1-session-cli configure ... @@ -596,6 +638,12 @@ async def parse_args() -> Tuple[argparse.Namespace,Configuration]: parser_new_provisioning_session.add_argument('-e', '--external-app-id', dest='app_id', metavar="APPLICATION-ID", help='The external application id to register the stream to', required=False) parser_new_provisioning_session.add_argument('-a','--asp-id', metavar="PROVIDER-ID", help="The Application Service Provider Id to use", required=False) + # m1-session-cli protocols -p + parser_protocols = subparsers.add_parser('protocols', help='Get the available upload/download protocols for a provisioning session') + parser_protocols.set_defaults(command=cmd_protocols) + parser_protocols.add_argument('-p', '--provisioning-session', + help='Provisioning session id to list the upload and download protocols for') + # m1-session-cli new-certificate -p [-d | --csr] parser_new_certificate = subparsers.add_parser('new-certificate', help='Create a new certificate') parser_new_certificate.set_defaults(command=cmd_new_certificate) @@ -689,6 +737,7 @@ async def main(): return 2 except Exception as err: print(f'General failure: {err}') + #traceback.print_exc() # add in for debugging return 2 return 0 From eea0dbeba7a0e20b6724b359768924cfa7ae2cae Mon Sep 17 00:00:00 2001 From: David Waring Date: Thu, 23 Mar 2023 17:15:38 +0000 Subject: [PATCH 43/48] Fix CHC updating and add show-stream command. --- tools/python3/lib/rt_m1_client/client.py | 22 ++------ tools/python3/lib/rt_m1_client/session.py | 14 +++++ tools/python3/m1_session_cli.py | 68 ++++++++++++++++++++--- 3 files changed, 79 insertions(+), 25 deletions(-) diff --git a/tools/python3/lib/rt_m1_client/client.py b/tools/python3/lib/rt_m1_client/client.py index 14fac43..36117de 100644 --- a/tools/python3/lib/rt_m1_client/client.py +++ b/tools/python3/lib/rt_m1_client/client.py @@ -250,8 +250,8 @@ async def retrieveContentHostingConfiguration(self, provisioning_session_id: Res return None async def updateContentHostingConfiguration(self, provisioning_session_id: ResourceId, - content_hosting_configuration: ContentHostingConfiguration - ) -> Union[bool,ContentHostingConfigurationResponse]: + content_hosting_configuration: ContentHostingConfiguration + ) -> bool: ''' Update a content hosting configuration for a provisioning session @@ -259,26 +259,14 @@ async def updateContentHostingConfiguration(self, provisioning_session_id: Resou for. :param ContentHostingConfiguration content_hosting_configuration: The new content hosting configuration to apply. - :return: a ContentHostingConfigurationResponse if the update succeeded and the new ContentHostingConfiguration was - returned by the M1 Server, or True if the update succeeded but no ContentHostingConfiguration was returned, - or False if the update failed. + :return: ``True`` if the update succeeded or ``False`` if the update failed. :raise M1ClientError: if there was a problem with the request. :raise M1ServerError: if there was a server side issue preventing the creation of the provisioning session. ''' - result = await self.__do_request('PUT', - f'/provisioning-sessions/{provisioning_session_id}/content-hosting-configuration', - - str(content_hosting_configuration), 'application/json') + result = await self.__do_request('PUT', f'/provisioning-sessions/{provisioning_session_id}/content-hosting-configuration', + json.dumps(content_hosting_configuration), 'application/json') if result['status_code'] == 204: - if len(result['body']) > 0: - ret: ContentHostingConfigurationResponse = self.__tag_and_date(result) - ret.update({ - 'ProvisioningSessionId': provisioning_session_id, - 'ContentHostingConfiguration': ContentHostingConfiguration.fromJSON( - result['body']) - }) - return ret return True if result['status_code'] == 404: return False diff --git a/tools/python3/lib/rt_m1_client/session.py b/tools/python3/lib/rt_m1_client/session.py index 255a818..874a259 100644 --- a/tools/python3/lib/rt_m1_client/session.py +++ b/tools/python3/lib/rt_m1_client/session.py @@ -363,6 +363,20 @@ async def contentHostingConfigurationGet(self, provisioning_session: ResourceId) return None return ContentHostingConfiguration(ps['content-hosting-configuration']['contenthostingconfiguration']) + async def contentHostingConfigurationUpdate(self, provisioning_session: ResourceId, chc: ContentHostingConfiguration) -> bool: + '''Update the `ContentHostingConfiguration` for a provisioning session + + :param provisioning_session: The provisioning session id of the provisioning session to set the + `ContentHostingConfiguration` in. + :param chc: The `ContentHostingConfiguration` to set in the provisioning session. + :return: ``True`` if the new `ContentHostingConfiguration` was successfully set in the provisioning session or ``False`` if + the operation failed (e.g. because there was no `ContentHostingConfiguration` set). + ''' + if provisioning_session not in self.__provisioning_sessions: + return False + await self.__connect() + return await self.__m1_client.updateContentHostingConfiguration(provisioning_session, chc) + # Convenience methods async def createDownlinkPullProvisioningSession(self, app_id: ApplicationId, asp_id: Optional[ApplicationId] = None) -> Optional[ResourceId]: diff --git a/tools/python3/m1_session_cli.py b/tools/python3/m1_session_cli.py index 134fb54..7dfea02 100755 --- a/tools/python3/m1_session_cli.py +++ b/tools/python3/m1_session_cli.py @@ -393,7 +393,16 @@ async def cmd_set_stream(args: argparse.Namespace, config: Configuration) -> int async with aiofiles.open(args.file, 'r') as json_in: chc = json.loads(await json_in.read()) - result = await session.contentHostingConfigurationCreate(provisioning_session_id, chc) + old_chc = await session.contentHostingConfigurationGet(provisioning_session_id) + if old_chc is None: + result = await session.contentHostingConfigurationCreate(provisioning_session_id, chc) + else: + # Remove any read-only fields + for dc in chc['distributionConfigurations']: + for strip_field in ['canonicalDomainName', 'baseURL']: + if strip_field in dc: + del dc[strip_field] + result = await session.contentHostingConfigurationUpdate(provisioning_session_id, chc) if not result: print(f'Failed to set hosting for provisioning session {provisioning_session_id}') return 1 @@ -444,6 +453,26 @@ async def cmd_delete_stream(args: argparse.Namespace, config: Configuration) -> print(f'Provisioning Session {ps_id} and all its resources were destroyed') return 0 +async def cmd_show_stream(args: argparse.Namespace, config: Configuration) -> int: + session = await get_session(config) + if args.provisioning_session is not None: + ps_id = args.provisioning_session + else: + ps_id = await session.provisioningSessionIdByIngestUrl(args.ingesturl, args.entrypoint) + if ps_id is None: + print('No such hosting session found') + return 1 + result = await session.contentHostingConfigurationGet(ps_id) + if result is None: + print(f'Provisioning Session {ps_id} does not have a ContentHostingConfiguration') + return 1 + if args.raw: + print(json.dumps(result, indent=2, sort_keys=True)) + else: + print(f'ContentHostingConfiguration for provisioning session {ps_id}:') + print('\n'.join([' '+line for line in ContentHostingConfiguration.format(result).split('\n')])) + return 0 + async def cmd_protocols(args: argparse.Namespace, config: Configuration) -> int: '''Perform ``protocols`` operation @@ -504,7 +533,11 @@ async def cmd_show_certificate(args: argparse.Namespace, config: Configuration) if result is None: print(f'Unable to get certificate {args.certificate_id} for provisioning session {args.provisioning_session}') return 1 - await __prettyPrintCertificate(result) + if args.raw: + print(result) + else: + print(f'Certificate details for {args.certificate_id}:') + await __prettyPrintCertificate(result, indent=2) return 0 async def cmd_set_certificate(args: argparse.Namespace, config: Configuration) -> int: @@ -629,20 +662,37 @@ async def parse_args() -> Tuple[argparse.Namespace,Configuration]: # m1-session-cli set-stream -p parser_set_stream = subparsers.add_parser('set-stream', help='Set the hosting for a provisioning session from a JSON file') parser_set_stream.set_defaults(command=cmd_set_stream) - parser_set_stream.add_argument('-p', '--provisioning-session', help='The provisioning session id to set the hosting for', required=True) + parser_set_stream.add_argument('-p', '--provisioning-session', help='The provisioning session id to set the hosting for', + required=True) parser_set_stream.add_argument('file', metavar='CHC-JSON-FILE', help='A filepath to a JSON encoded ContentHostingConfiguration') + # m1-session-cli show-stream (-p | []) [-r] + parser_show_stream = subparsers.add_parser('show-stream', + help='Display the ContentHostingConfiguration for a provisioning session') + parser_show_stream.set_defaults(command=cmd_show_stream) + parser_show_stream_filter = parser_show_stream.add_mutually_exclusive_group(required=True) + parser_show_stream_filter.add_argument('-p', '--provisioning-session', help='The provisioning session id to show', + required=False) + parser_show_stream_filter.add_argument('ingesturl', metavar='ingest-URL', nargs='?', help='The ingest URL prefix used') + parser_show_stream.add_argument('entrypoint', metavar='entry-point-path', nargs='?', + help='The media player entry point suffix.') + parser_show_stream.add_argument('-r', '--raw', required=False, action="store_true", + help='Use "raw" output mode to present the ContentHostingConfiguration JSON') + # m1-session-cli new-provisioning-session [-e ] [-a ] parser_new_provisioning_session = subparsers.add_parser('new-provisioning-session', help='Create a new provisioning session') parser_new_provisioning_session.set_defaults(command=cmd_new_provisioning_session) - parser_new_provisioning_session.add_argument('-e', '--external-app-id', dest='app_id', metavar="APPLICATION-ID", help='The external application id to register the stream to', required=False) - parser_new_provisioning_session.add_argument('-a','--asp-id', metavar="PROVIDER-ID", help="The Application Service Provider Id to use", required=False) + parser_new_provisioning_session.add_argument('-e', '--external-app-id', dest='app_id', metavar="APPLICATION-ID", + help='The external application id to register the stream to', required=False) + parser_new_provisioning_session.add_argument('-a','--asp-id', metavar="PROVIDER-ID", + help="The Application Service Provider Id to use", required=False) # m1-session-cli protocols -p - parser_protocols = subparsers.add_parser('protocols', help='Get the available upload/download protocols for a provisioning session') + parser_protocols = subparsers.add_parser('protocols', + help='Get the available upload/download protocols for a provisioning session') parser_protocols.set_defaults(command=cmd_protocols) parser_protocols.add_argument('-p', '--provisioning-session', - help='Provisioning session id to list the upload and download protocols for') + help='Provisioning session id to list the upload and download protocols for') # m1-session-cli new-certificate -p [-d | --csr] parser_new_certificate = subparsers.add_parser('new-certificate', help='Create a new certificate') @@ -662,6 +712,8 @@ async def parse_args() -> Tuple[argparse.Namespace,Configuration]: help='Provisioning session id to show the certificate for') parser_show_certificate.add_argument('-c', '--certificate-id', required=True, help='The certificate id of the certificate to show') + parser_show_certificate.add_argument('-r', '--raw', required=False, action="store_true", + help='Use "raw" output mode to present the public certificate PEM data') # m1-session-cli set-certificate -p -c [] parser_set_certificate = subparsers.add_parser('set-certificate', @@ -737,7 +789,7 @@ async def main(): return 2 except Exception as err: print(f'General failure: {err}') - #traceback.print_exc() # add in for debugging + traceback.print_exc() # add in for debugging return 2 return 0 From 7016a21a4f5ef32f724bcfb443e4bef96e7448a7 Mon Sep 17 00:00:00 2001 From: David Waring Date: Thu, 23 Mar 2023 17:17:36 +0000 Subject: [PATCH 44/48] Fix list node management, check CHC parsing and add const correctness to some functions. --- src/5gmsaf/application-server-context.c | 65 +++++++++++----- src/5gmsaf/msaf-m1-sm.c | 34 +++++---- src/5gmsaf/provisioning-session.c | 98 ++++++++++--------------- src/5gmsaf/provisioning-session.h | 24 +++--- 4 files changed, 121 insertions(+), 100 deletions(-) diff --git a/src/5gmsaf/application-server-context.c b/src/5gmsaf/application-server-context.c index f185bc0..6d9ebfa 100644 --- a/src/5gmsaf/application-server-context.c +++ b/src/5gmsaf/application-server-context.c @@ -23,7 +23,7 @@ typedef struct client_request_info { static void application_server_state_init(msaf_application_server_node_t *msaf_as); static ogs_sbi_client_t *msaf_m3_client_init(const char *hostname, int port); -static int +static int m3_client_as_state_requests(msaf_application_server_state_node_t *as_state, purge_resource_id_node_t *purge_node,const char *type, const char *data, const char *method, const char *component); static int client_notify_cb(int status, ogs_sbi_response_t *response, void *data); static void msaf_application_server_remove(msaf_application_server_node_t *msaf_as); @@ -43,11 +43,13 @@ msaf_application_server_state_set_on_post( msaf_provisioning_session_t *provisio msaf_as = ogs_list_first(&msaf_self()->config.applicationServers_list); ogs_assert(msaf_as); ogs_list_for_each(&msaf_self()->application_server_states, as_state){ - if(!strcmp(as_state->application_server->canonicalHostname, msaf_as->canonicalHostname)) { + if (as_state->application_server == msaf_as) { + msaf_application_server_state_ref_node_t *as_state_ref; certs = msaf_retrieve_certificates_from_map(provisioning_session); if (certs) { ogs_list_for_each_safe(certs, next_node, node) { + ogs_list_remove(certs, node); ogs_list_add(&as_state->upload_certificates, node); } ogs_free(certs); @@ -59,14 +61,17 @@ msaf_application_server_state_set_on_post( msaf_provisioning_session_t *provisio ogs_assert(chc); chc->state = ogs_strdup(provisioning_session->provisioningSessionId); ogs_list_add(&as_state->upload_content_hosting_configurations, chc); + assigned_provisioning_sessions = ogs_calloc(1, sizeof(assigned_provisioning_sessions_node_t)); ogs_assert(assigned_provisioning_sessions); assigned_provisioning_sessions->assigned_provisioning_session = provisioning_session; - assigned_provisioning_sessions->assigned_provisioning_session->contentHostingConfiguration = provisioning_session->contentHostingConfiguration; ogs_list_add(&as_state->assigned_provisioning_sessions, assigned_provisioning_sessions); - ogs_list_init(&provisioning_session->msaf_application_server_state_nodes); - ogs_list_add(&provisioning_session->msaf_application_server_state_nodes, as_state); + ogs_list_init(&provisioning_session->application_server_states); + as_state_ref = ogs_calloc(1, sizeof(msaf_application_server_state_ref_node_t)); + ogs_assert(as_state_ref); + as_state_ref->as_state = as_state; + ogs_list_add(&provisioning_session->application_server_states, as_state_ref); next_action_for_application_server(as_state); } @@ -77,22 +82,47 @@ msaf_application_server_state_set_on_post( msaf_provisioning_session_t *provisio void msaf_application_server_state_update( msaf_provisioning_session_t *provisioning_session) { - msaf_application_server_state_node_t *as_state; - resource_id_node_t *chc; - assigned_provisioning_sessions_node_t *assigned_provisioning_sessions; + msaf_application_server_state_ref_node_t *as_state_ref; + + ogs_list_for_each(&provisioning_session->application_server_states, as_state_ref){ + resource_id_node_t *chc; + msaf_application_server_state_node_t *as_state = as_state_ref->as_state; + ogs_list_t *certs = msaf_retrieve_certificates_from_map(provisioning_session); + if (certs) { + resource_id_node_t *next_node, *node; + ogs_list_for_each_safe(certs, next_node, node) { + int upload_cert = 1; + resource_id_node_t *cur_cert; + /* Check if the certificate is already uploaded */ + ogs_list_for_each(as_state->current_certificates, cur_cert) { + if (!strcmp(node->state, cur_cert->state)) { + upload_cert = 0; + break; + } + + } + /* If there is a new certificate for this AS, upload it */ + if (upload_cert) { + ogs_list_remove(certs, node); + ogs_list_add(&as_state->upload_certificates, node); + } + } + /* free any cert map nodes left in the list (didn't need update) */ + ogs_list_for_each_safe(certs, next_node, node) { + ogs_list_remove(certs, node); + if (node->state) ogs_free(node->state); + ogs_free(node); + } + ogs_free(certs); + } else { + continue; + } - ogs_list_for_each(&provisioning_session->msaf_application_server_state_nodes, as_state){ chc = ogs_calloc(1, sizeof(resource_id_node_t)); ogs_assert(chc); chc->state = ogs_strdup(provisioning_session->provisioningSessionId); ogs_list_add(&as_state->upload_content_hosting_configurations, chc); - ogs_list_for_each(&as_state->assigned_provisioning_sessions,assigned_provisioning_sessions){ - - assigned_provisioning_sessions->assigned_provisioning_session = provisioning_session; - assigned_provisioning_sessions->assigned_provisioning_session->contentHostingConfiguration = provisioning_session->contentHostingConfiguration; - } - next_action_for_application_server(as_state); } } @@ -108,6 +138,7 @@ msaf_application_server_state_set(msaf_application_server_state_node_t *as_state certs = msaf_retrieve_certificates_from_map(provisioning_session); if (certs) { ogs_list_for_each_safe(certs, next_node, node) { + ogs_list_remove(certs, node); ogs_list_add(&as_state->upload_certificates, node); } ogs_free(certs); @@ -261,9 +292,9 @@ void next_action_for_application_server(msaf_application_server_state_node_t *as ogs_debug("M3 client: Sending Purge operation for cache [%s] to the Application Server", purge_chc->provisioning_session_id); m3_client_as_state_requests(as_state, purge_chc, "application/x-www-form-urlencoded", NULL, OGS_SBI_HTTP_METHOD_POST, component); } - ogs_free(component); + ogs_free(component); - } + } } diff --git a/src/5gmsaf/msaf-m1-sm.c b/src/5gmsaf/msaf-m1-sm.c index a329c3a..39d7ba4 100644 --- a/src/5gmsaf/msaf-m1-sm.c +++ b/src/5gmsaf/msaf-m1-sm.c @@ -168,16 +168,17 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) if(msaf_provisioning_session) { // process the POST body purge_resource_id_node_t *purge_cache; - msaf_application_server_state_node_t *as_state; + msaf_application_server_state_ref_node_t *as_state_ref; assigned_provisioning_sessions_node_t *assigned_provisioning_sessions_resource; m1_purge_information_t *m1_purge_info = ogs_calloc(1, sizeof(m1_purge_information_t)); m1_purge_info->m1_stream = stream; m1_purge_info->m1_message = message; - ogs_list_for_each(&msaf_provisioning_session->msaf_application_server_state_nodes, as_state) { - if(as_state->application_server && as_state->application_server->canonicalHostname) { + ogs_list_for_each(&msaf_provisioning_session->application_server_states, as_state_ref) { + msaf_application_server_state_node_t *as_state = as_state_ref->as_state; + if (as_state->application_server && as_state->application_server->canonicalHostname) { ogs_list_for_each(&as_state->assigned_provisioning_sessions,assigned_provisioning_sessions_resource){ - if(!strcmp(assigned_provisioning_sessions_resource->assigned_provisioning_session->provisioningSessionId, msaf_provisioning_session->provisioningSessionId)) { + if(assigned_provisioning_sessions_resource->assigned_provisioning_session == msaf_provisioning_session) { purge_cache = ogs_calloc(1, sizeof(purge_resource_id_node_t)); ogs_assert(purge_cache); @@ -357,11 +358,6 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) break; } - if (ogs_list_first(&msaf_provisioning_session->msaf_application_servers) == NULL) { - ogs_list_init(&msaf_provisioning_session->msaf_application_server_state_nodes); - ogs_list_add(&msaf_provisioning_session->msaf_application_server_state_nodes, msaf_as); - } - cert = check_in_cert_list(canonical_domain_name); if (cert != NULL) { ogs_sbi_response_t *response; @@ -651,12 +647,24 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) ogs_info("PUT: with msaf_provisioning_session: %s", message.h.resource.component[1]); if (!strcmp(message.h.resource.component[2],"content-hosting-configuration") && !message.h.resource.component[3]) { - // process the POST body + // process the PUT body cJSON *entry; int rv; cJSON *content_hosting_config = cJSON_Parse(request->http.content); - char *txt = cJSON_Print(content_hosting_config); - ogs_debug("txt:%s", txt); + + if (!content_hosting_config) { + char *err = NULL; + asprintf(&err,"While updating the Content Hosting Configuration for the Provisioning Session [%s], Failure parsing ContentHostingConfiguration JSON.",message.h.resource.component[1]); + ogs_error("%s", err); + ogs_assert(true == nf_server_send_error(stream, 422, 2, &message, "Bad ContentHosting Configuration JSON.", err, NULL, m1_contenthostingprovisioning_api, app_meta)); + break; + } + + { + char *txt = cJSON_Print(content_hosting_config); + ogs_debug("txt:%s", txt); + ogs_free(txt); + } cJSON_ArrayForEach(entry, content_hosting_config) { if(!strcmp(entry->string, "entryPointPath")){ @@ -888,7 +896,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e) nf_server_populate_response(response, 0, NULL, 202); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); msaf_delete_content_hosting_configuration(message.h.resource.component[1]); - msaf_delete_certificate(message.h.resource.component[1]); + msaf_delete_certificates(message.h.resource.component[1]); msaf_context_provisioning_session_free(provisioning_session); msaf_provisioning_session_hash_remove(message.h.resource.component[1]); } diff --git a/src/5gmsaf/provisioning-session.c b/src/5gmsaf/provisioning-session.c index 5ec3fd0..2a25e99 100644 --- a/src/5gmsaf/provisioning-session.c +++ b/src/5gmsaf/provisioning-session.c @@ -19,12 +19,12 @@ program. If this file is missing then the license can be retrieved from #include "provisioning-session.h" typedef struct free_ogs_hash_provisioning_session_s { - char *provisioning_session; + const char *provisioning_session; ogs_hash_t *hash; } free_ogs_hash_provisioning_session_t; typedef struct free_ogs_hash_provisioning_session_certificate_s { - char *certificate; + const char *certificate; ogs_hash_t *hash; } free_ogs_hash_provisioning_session_certificate_t; @@ -69,7 +69,7 @@ msaf_content_hosting_configuration_with_af_unique_cert_id(msaf_provisioning_sess msaf_provisioning_session_t * msaf_provisioning_session_create(const char *provisioning_session_type, const char *asp_id, const char *external_app_id) { - msaf_provisioning_session_t *msaf_provisioning_session; + msaf_provisioning_session_t *msaf_provisioning_session; ogs_uuid_t uuid; char id[OGS_UUID_FORMATTED_LENGTH + 1]; OpenAPI_provisioning_session_t *provisioning_session; @@ -175,78 +175,56 @@ msaf_content_hosting_configuration_certificate_check(msaf_provisioning_session_t } void -msaf_delete_certificate(char *resource_id) +msaf_delete_certificates(const char *provisioning_session_id) { - msaf_application_server_state_node_t *as_state; + ogs_list_for_each(&msaf_self()->application_server_states, as_state) { - resource_id_node_t *certificate, *next = NULL; - resource_id_node_t *upload_certificate, *next_node = NULL; - resource_id_node_t *delete_cert = NULL; - ogs_list_init(&as_state->delete_certificates); + resource_id_node_t *upload_certificate, *next_node; + /* delete certificates already on the AS */ if (as_state->current_certificates) { - - char *current_cert_id; - char *provisioning_session; - char *cert_id; + resource_id_node_t *certificate, *next; ogs_list_for_each_safe(as_state->current_certificates, next, certificate){ + char *cert_id; + char *provisioning_session; + char *current_cert_id = ogs_strdup(certificate->state); - current_cert_id = ogs_strdup(certificate->state); provisioning_session = strtok_r(current_cert_id,":",&cert_id); - if(!strcmp(provisioning_session, resource_id)) - break; + if(!strcmp(provisioning_session, provisioning_session_id)) { + /* provisioning session matches */ + resource_id_node_t *delete_cert; + delete_cert = ogs_calloc(1, sizeof(resource_id_node_t)); + ogs_assert(delete_cert); + delete_cert->state = ogs_strdup(certificate->state); + ogs_list_add(&as_state->delete_certificates, delete_cert); + } if(current_cert_id) ogs_free(current_cert_id); - - } - - if (certificate) { - delete_cert = ogs_calloc(1, sizeof(resource_id_node_t)); - ogs_assert(delete_cert); - delete_cert->state = ogs_strdup(certificate->state); - ogs_list_add(&as_state->delete_certificates, delete_cert); - } - - if (current_cert_id) - ogs_free(current_cert_id); } - { - - char *upload_cert_id = NULL; - char *provisioning_session; + /* remove entries from upload queue and try to delete just to be safe */ + ogs_list_for_each_safe(&as_state->upload_certificates, next_node, upload_certificate) { char *cert_id; + char *upload_cert_id = ogs_strdup(upload_certificate->state); + char *provisioning_session = strtok_r(upload_cert_id,":",&cert_id); - ogs_list_for_each_safe(&as_state->upload_certificates, next_node, upload_certificate) { - - upload_cert_id = ogs_strdup(upload_certificate->state); - provisioning_session = strtok_r(upload_cert_id,":",&cert_id); - if(!strcmp(provisioning_session, resource_id)) - break; - } - - if (upload_certificate) { - + if (!strcmp(provisioning_session, provisioning_session_id)) { ogs_list_remove(&as_state->upload_certificates, upload_certificate); - ogs_list_add(&as_state->delete_certificates, upload_certificate); - } - - if(upload_cert_id) + if (upload_cert_id) ogs_free(upload_cert_id); } - } } void -msaf_delete_content_hosting_configuration(char *resource_id) +msaf_delete_content_hosting_configuration(const char *provisioning_session_id) { msaf_application_server_state_node_t *as_state; @@ -262,7 +240,7 @@ msaf_delete_content_hosting_configuration(char *resource_id) ogs_list_for_each_safe(as_state->current_content_hosting_configurations, next, content_hosting_configuration){ - if (!strcmp(content_hosting_configuration->state, resource_id)) + if (!strcmp(content_hosting_configuration->state, provisioning_session_id)) break; } if (content_hosting_configuration) { @@ -275,7 +253,7 @@ msaf_delete_content_hosting_configuration(char *resource_id) } ogs_list_for_each_safe(&as_state->upload_content_hosting_configurations, next_node, upload_content_hosting_configuration){ - if (!strcmp(upload_content_hosting_configuration->state, resource_id)) + if (!strcmp(upload_content_hosting_configuration->state, provisioning_session_id)) break; } if (upload_content_hosting_configuration) { @@ -366,7 +344,7 @@ msaf_distribution_create(cJSON *content_hosting_config, msaf_provisioning_sessio { OpenAPI_lnode_t *dist_config_node = NULL; OpenAPI_distribution_configuration_t *dist_config = NULL; - char *url_path; + char *url_path; char *domain_name; char *media_player_entry; static const char macro[] = "{provisioningSessionId}"; @@ -416,18 +394,18 @@ msaf_distribution_create(cJSON *content_hosting_config, msaf_provisioning_sessio ogs_error("The Content Hosting Configuration has no Distribution Configuration"); } if (content_hosting_configuration->entry_point_path) { - + media_player_entry = ogs_msprintf("%s%s", dist_config->base_url, content_hosting_configuration->entry_point_path); } else { - ogs_debug("The contentHostingConfiguration has no entryPointPath"); + ogs_debug("The contentHostingConfiguration has no entryPointPath"); } if(media_player_entry) { provisioning_session->serviceAccessInformation = msaf_context_service_access_information_create(provisioning_session->provisioningSessionId, media_player_entry); - provisioning_session->serviceAccessInformationCreated = time(NULL); + provisioning_session->serviceAccessInformationCreated = time(NULL); provisioning_session->serviceAccessInformationHash = ogs_strdup(calculate_service_access_information_hash(provisioning_session->serviceAccessInformation)); } else { - ogs_debug("Couldn't formulate serviceAccessInformation as media Player Entry is not formulated"); + ogs_debug("Couldn't formulate serviceAccessInformation as media Player Entry is not formulated"); } provisioning_session->contentHostingConfiguration = content_hosting_configuration; if(provisioning_session->contentHostingConfiguration) @@ -442,7 +420,7 @@ msaf_distribution_create(cJSON *content_hosting_config, msaf_provisioning_sessio return 1; } -cJSON *msaf_get_content_hosting_configuration_by_provisioning_session_id(char *provisioning_session_id) { +cJSON *msaf_get_content_hosting_configuration_by_provisioning_session_id(const char *provisioning_session_id) { msaf_provisioning_session_t *msaf_provisioning_session; cJSON *content_hosting_configuration_json; @@ -460,7 +438,7 @@ cJSON *msaf_get_content_hosting_configuration_by_provisioning_session_id(char *p } void -msaf_provisioning_session_hash_remove(char *provisioning_session_id) +msaf_provisioning_session_hash_remove(const char *provisioning_session_id) { free_ogs_hash_provisioning_session_t fohps = { provisioning_session_id, @@ -470,7 +448,7 @@ msaf_provisioning_session_hash_remove(char *provisioning_session_id) } void -msaf_provisioning_session_certificate_hash_remove(char *provisioning_session_id, char *certificate_id) +msaf_provisioning_session_certificate_hash_remove(const char *provisioning_session_id, const char *certificate_id) { msaf_provisioning_session_t *provisioning_session = NULL; provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(provisioning_session_id); @@ -482,7 +460,7 @@ msaf_provisioning_session_certificate_hash_remove(char *provisioning_session_id, ogs_hash_do(free_ogs_hash_provisioning_session_certificate, &fohpsc, provisioning_session->certificate_map); } -int uri_relative_check(char *entry_point_path) +int uri_relative_check(const char *entry_point_path) { int result; @@ -528,7 +506,7 @@ char *enumerate_provisioning_sessions(void) { ogs_hash_index_t *hi; char *provisioning_sessions = "[]"; - int number_of_provisioning_sessions = ogs_hash_count(msaf_self()->provisioningSessions_map); + int number_of_provisioning_sessions = ogs_hash_count(msaf_self()->provisioningSessions_map); if (number_of_provisioning_sessions) { provisioning_sessions = ogs_calloc(1, (4 + (sizeof(char)*(OGS_UUID_FORMATTED_LENGTH + 1) *number_of_provisioning_sessions) +1)); diff --git a/src/5gmsaf/provisioning-session.h b/src/5gmsaf/provisioning-session.h index 9c219b9..ad4a9ec 100644 --- a/src/5gmsaf/provisioning-session.h +++ b/src/5gmsaf/provisioning-session.h @@ -34,13 +34,17 @@ typedef struct msaf_provisioning_session_s { char *contentHostingConfigurationHash; time_t serviceAccessInformationCreated; char *serviceAccessInformationHash; - /*ogs_list_t certificates; //Nodes for this list are msaf_assigned_certificate_t * */ - ogs_hash_t *certificate_map; - ogs_list_t msaf_application_servers; // Nodes for this list are msaf_application_server_node_t * - ogs_list_t msaf_application_server_state_nodes; //Nodes for this list are msaf_application_server_state_node_t * + ogs_hash_t *certificate_map; + ogs_list_t application_server_states; //Type: msaf_application_server_state_ref_node_t * int marked_for_deletion; } msaf_provisioning_session_t; +typedef struct msaf_application_server_state_node_s msaf_application_server_state_node_t; +typedef struct msaf_application_server_state_ref_node_s { + ogs_lnode_t node; + msaf_application_server_state_node_t *as_state; +} msaf_application_server_state_ref_node_t; + extern msaf_provisioning_session_t *msaf_provisioning_session_create(const char *provisioning_session_type, const char *asp_id, const char *external_app_id); extern msaf_provisioning_session_t *msaf_provisioning_session_find_by_provisioningSessionId(const char *provisioningSessionId); extern cJSON *msaf_provisioning_session_get_json(const char *provisioning_session_id); @@ -56,20 +60,20 @@ extern ogs_list_t *msaf_retrieve_certificates_from_map(msaf_provisioning_session extern OpenAPI_content_hosting_configuration_t *msaf_content_hosting_configuration_with_af_unique_cert_id(msaf_provisioning_session_t *provisioning_session); -extern void msaf_delete_content_hosting_configuration(char * resource_id); +extern void msaf_delete_content_hosting_configuration(const char *provisioning_session_id); -extern void msaf_delete_certificate(char *resource_id); +extern void msaf_delete_certificates(const char *provisioning_session_id); -extern void msaf_provisioning_session_hash_remove(char *provisioning_session_id); +extern void msaf_provisioning_session_hash_remove(const char *provisioning_session_id); -extern void msaf_provisioning_session_certificate_hash_remove(char *provisioning_session_id, char *certificate_id); +extern void msaf_provisioning_session_certificate_hash_remove(const char *provisioning_session_id, const char *certificate_id); -extern int uri_relative_check(char *entry_point_path); +extern int uri_relative_check(const char *entry_point_path); extern int msaf_distribution_create(cJSON *content_hosting_config, msaf_provisioning_session_t *provisioning_session); -extern cJSON *msaf_get_content_hosting_configuration_by_provisioning_session_id(char *provisioning_session_id); +extern cJSON *msaf_get_content_hosting_configuration_by_provisioning_session_id(const char *provisioning_session_id); extern char *enumerate_provisioning_sessions(void); From 4a80488e13ccc36732247fdd26b0df0ed21b6eb9 Mon Sep 17 00:00:00 2001 From: David Waring Date: Thu, 23 Mar 2023 17:50:09 +0000 Subject: [PATCH 45/48] Adjust the example files to suit the new M1 interface. --- examples/Certificates.json | 3 -- ...ull-ingest_domain-name_http_and_https.json | 18 ------- ...unny_pull-ingest_http_and_https.json.tmpl} | 2 +- ...tion_Big-Buck-Bunny_pull-ingest_https.json | 14 ----- ...ig-Buck-Bunny_pull-ingest_https.json.tmpl} | 2 +- examples/README.md | 54 +++---------------- examples/Test_http_canonical-msaf.yaml | 28 ---------- examples/Test_http_domain_alias-msaf.yaml | 28 ---------- examples/Test_https_canonical-msaf.yaml | 28 ---------- examples/Test_https_domain_alias-msaf.yaml | 28 ---------- 10 files changed, 8 insertions(+), 197 deletions(-) delete mode 100644 examples/Certificates.json delete mode 100644 examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_domain-name_http_and_https.json rename examples/{ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_http_and_https.json => ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_http_and_https.json.tmpl} (89%) delete mode 100644 examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_https.json rename examples/{ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_domain-name_http.json => ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_https.json.tmpl} (88%) delete mode 100644 examples/Test_http_canonical-msaf.yaml delete mode 100644 examples/Test_http_domain_alias-msaf.yaml delete mode 100644 examples/Test_https_canonical-msaf.yaml delete mode 100644 examples/Test_https_domain_alias-msaf.yaml diff --git a/examples/Certificates.json b/examples/Certificates.json deleted file mode 100644 index c9bc6a4..0000000 --- a/examples/Certificates.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "testcert1": "certificate-1.pem" -} diff --git a/examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_domain-name_http_and_https.json b/examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_domain-name_http_and_https.json deleted file mode 100644 index 501a5fd..0000000 --- a/examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_domain-name_http_and_https.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "Big Buck Bunny", - "entryPointPath": "BigBuckBunny_4s_onDemand_2014_05_09.mpd", - "ingestConfiguration": { - "pull": true, - "protocol": "urn:3gpp:5gms:content-protocol:http-pull-ingest", - "baseURL": "https://ftp.itec.aau.at/datasets/DASHDataset2014/BigBuckBunny/4sec/" - }, - "distributionConfigurations": [ - { - "domainNameAlias": "media.example.com" - }, - { - "domainNameAlias": "media.example.com", - "certificateId": "testcert1" - } - ] -} diff --git a/examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_http_and_https.json b/examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_http_and_https.json.tmpl similarity index 89% rename from examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_http_and_https.json rename to examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_http_and_https.json.tmpl index 0bf4390..f0e0c42 100644 --- a/examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_http_and_https.json +++ b/examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_http_and_https.json.tmpl @@ -9,7 +9,7 @@ "distributionConfigurations": [ {}, { - "certificateId": "testcert1" + "certificateId": "@certificate-id@" } ] } diff --git a/examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_https.json b/examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_https.json deleted file mode 100644 index 3752bc8..0000000 --- a/examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_https.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "Big Buck Bunny", - "entryPointPath": "BigBuckBunny_4s_onDemand_2014_05_09.mpd", - "ingestConfiguration": { - "pull": true, - "protocol": "urn:3gpp:5gms:content-protocol:http-pull-ingest", - "baseURL": "https://ftp.itec.aau.at/datasets/DASHDataset2014/BigBuckBunny/4sec/" - }, - "distributionConfigurations": [ - { - "certificateId": "testcert1" - } - ] -} diff --git a/examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_domain-name_http.json b/examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_https.json.tmpl similarity index 88% rename from examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_domain-name_http.json rename to examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_https.json.tmpl index 3383f29..13c4e1e 100644 --- a/examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_domain-name_http.json +++ b/examples/ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_https.json.tmpl @@ -7,6 +7,6 @@ "baseURL": "https://ftp.itec.aau.at/datasets/DASHDataset2014/BigBuckBunny/4sec/" }, "distributionConfigurations": [ - {"domainNameAlias": "media.example.com"} + { "certificateId": "@certificate-id@" } ] } diff --git a/examples/README.md b/examples/README.md index 27873cb..041b7a2 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,21 +1,6 @@ # 5G-MAG Reference Tools: 5GMS Application Function Example Configurations -This directory contains examples of configuration files for the 5GMS Application Function. - -## `Certificates.json` - -This file contains a mapping from certificate ID to certificate filename. The -certificate IDs in this file are used to find the matching certificate file -(containing a public certificate, private key and any intermediate CA -certificates) when referenced from a ContentHostingConfiguration file. - -The `subprojects/rt-common-shared/5gms/scripts/make_self_signed_certs.py` script can be used, passing a 5GMS Application Function YAML configuration file as a parameter, to create suitable self-signed certificate files for testing purposes. - -For example: -```bash -cd ~/rt-5gms-application-function -subprojects/rt-common-shared/5gms/scripts/make_self_signed_certs.py --af-conf=examples/Test_https_canonical-msaf.yaml -``` +This directory contains examples of configurations for the 5GMS Application Function. ## `ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest.json` @@ -25,38 +10,11 @@ It contains a ContentHostingConfiguration, based on 3GPP TS 26.512 Release 17.3. The distribution side of the configurations tells the rt-5gms-application-function to configure a 5GMS Application Server to reverse proxy the media on its localhost (127.0.0.1) loopback interface. The distribution configuration object is left empty as this is a simple distribution where all fields are generated by the 5GMS Application Function. Note that there needs to be at least one entry in `distributionConfigurations`, even if it is an empty object. -## `ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_http_and_https.json` - -This file is an alternative to `ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest.json` (see above) and can be used along with the `Certificates.json` file to configure a rt-5gms-application-function to provision a 5GMS Application Server which will provide both HTTP and HTTPS distribution points. - -## `ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_https.json` - -This file is an alternative to `ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest.json` (see above) and can be used along with the `Certificates.json` file to run a rt-5gms-application-function to provision a 5GMS Application Server which will provide an HTTPS distribution point only. - -## `ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_domain-name_http.json` - -This file is the same as `ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest.json` except that the distribution configuration also has "media.example.com" as a domain name alias. This file is included for testing the portions of the Application Function that should prefer the use of the domain name alias over the canonical name or vice-versa. - -## `ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_domain-name_http_and_https.json` - -This file is the same as `ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_http_and_https.json` except that the distribution configuration also has "media.example.com" as a domain name alias. This file is included for testing the portions of the Application Function that should prefer the use of the domain name alias over the canonical name or vice-versa. - -## `Test_http_canonical-msaf.yaml` - -This is a 5GMS Application Function YAML configuration file used for testing. This configuration uses the `ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest.json` ContentHostingConfiguration to test http protocol distribution using `localhost` as the canonical domain name of the Application Server. - -## `Test_http_domain_alias-msaf.yaml` - -This is a 5GMS Application Function YAML configuration file used for testing. This configuration uses the `ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_domain-name_http.json` ContentHostingConfiguration to test http protocol distribution using `localhost` as the canonical domain name of the Application Server and `media.example.com` as a domain name alias for the distribution configuration. - -## `Test_https_canonical-msaf.yaml` - -This is a 5GMS Application Function YAML configuration file used for testing. This configuration uses the `ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_http_and_https.json` ContentHostingConfiguration and the `Certificates.json` certificates index file to test https protocol distribution using `localhost` as the canonical domain name of the Application Server. - -Generate the certificates before using the configuration file. See [`Certificates.json`](#certificatesjson) for more information. +## `ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_http_and_https.json.tmpl` -## `Test_https_domain_alias-msaf.yaml` +This template file is an alternative to `ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest.json` (see above) and can be used to configure a rt-5gms-application-function to provision a 5GMS Application Server which will provide both HTTP and HTTPS distribution points. Before the contents of this file can be used as a configuration `@certificate-id@` must be substituted for a valid certificate id for the provisioning session you wish to add the configuration to. -This is a 5GMS Application Function YAML configuration file used for testing. This configuration uses the `ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_domain-name_http_and_https.json` ContentHostingConfiguration and the `Certificates.json` certificates index file to test https protocol distribution using `localhost` as the canonical domain name of the Application Server and `media.example.com` as a domain name alias for the distribution configurations. +## `ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_https.json.tmpl` -Generate the certificates before using the configuration file. See [`Certificates.json`](#certificatesjson) for more information. +This template file is an alternative to `ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest.json` (see above) and can be used to configure a rt-5gms-application-function to provision a 5GMS Application Server which will provide an HTTPS distribution point only. Before the contents of this file can be used as a configuration `@certificate-id@` must be substituted for a valid certific +ate id for the provisioning session you wish to add the configuration to. diff --git a/examples/Test_http_canonical-msaf.yaml b/examples/Test_http_canonical-msaf.yaml deleted file mode 100644 index af4affc..0000000 --- a/examples/Test_http_canonical-msaf.yaml +++ /dev/null @@ -1,28 +0,0 @@ -logger: - level: debug - domain: msaf - -msaf: - open5gsIntegration: false - sbi: - - addr: 0.0.0.0 - port: 7778 - applicationServers: - - canonicalHostname: localhost - urlPathPrefixFormat: /m4d/provisioning-session-{provisioningSessionId}/ - m3Port: 7777 - certificate: Certificates.json - contentHostingConfiguration: ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest.json - -nrf: - sbi: - - addr: - - 127.0.0.10 - - ::1 - port: 7777 - -parameter: - -max: - -time: diff --git a/examples/Test_http_domain_alias-msaf.yaml b/examples/Test_http_domain_alias-msaf.yaml deleted file mode 100644 index 7cd6dac..0000000 --- a/examples/Test_http_domain_alias-msaf.yaml +++ /dev/null @@ -1,28 +0,0 @@ -logger: - level: debug - domain: msaf - -msaf: - open5gsIntegration: false - sbi: - - addr: 0.0.0.0 - port: 7778 - applicationServers: - - canonicalHostname: localhost - urlPathPrefixFormat: /m4d/provisioning-session-{provisioningSessionId}/ - m3Port: 7777 - certificate: Certificates.json - contentHostingConfiguration: ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_domain-name_http.json - -nrf: - sbi: - - addr: - - 127.0.0.10 - - ::1 - port: 7777 - -parameter: - -max: - -time: diff --git a/examples/Test_https_canonical-msaf.yaml b/examples/Test_https_canonical-msaf.yaml deleted file mode 100644 index b00171b..0000000 --- a/examples/Test_https_canonical-msaf.yaml +++ /dev/null @@ -1,28 +0,0 @@ -logger: - level: debug - domain: msaf - -msaf: - open5gsIntegration: false - sbi: - - addr: 0.0.0.0 - port: 7778 - applicationServers: - - canonicalHostname: localhost - urlPathPrefixFormat: /m4d/provisioning-session-{provisioningSessionId}/ - m3Port: 7777 - certificate: Certificates.json - contentHostingConfiguration: ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_http_and_https.json - -nrf: - sbi: - - addr: - - 127.0.0.10 - - ::1 - port: 7777 - -parameter: - -max: - -time: diff --git a/examples/Test_https_domain_alias-msaf.yaml b/examples/Test_https_domain_alias-msaf.yaml deleted file mode 100644 index 6140003..0000000 --- a/examples/Test_https_domain_alias-msaf.yaml +++ /dev/null @@ -1,28 +0,0 @@ -logger: - level: debug - domain: msaf - -msaf: - open5gsIntegration: false - sbi: - - addr: 0.0.0.0 - port: 7778 - applicationServers: - - canonicalHostname: localhost - urlPathPrefixFormat: /m4d/provisioning-session-{provisioningSessionId}/ - m3Port: 7777 - certificate: Certificates.json - contentHostingConfiguration: ContentHostingConfiguration_Big-Buck-Bunny_pull-ingest_domain-name_http_and_https.json - -nrf: - sbi: - - addr: - - 127.0.0.10 - - ::1 - port: 7777 - -parameter: - -max: - -time: From a5ee3b461d4930120e2e5b97e080324f3ae5adf4 Mon Sep 17 00:00:00 2001 From: David Waring Date: Thu, 23 Mar 2023 18:01:08 +0000 Subject: [PATCH 46/48] Free the AS state reference when the provisioning session is freed --- src/5gmsaf/context.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/5gmsaf/context.c b/src/5gmsaf/context.c index f805ff1..72020bf 100644 --- a/src/5gmsaf/context.c +++ b/src/5gmsaf/context.c @@ -678,6 +678,8 @@ free_ogs_hash_entry(void *rec, const void *key, int klen, const void *value) void msaf_context_provisioning_session_free(msaf_provisioning_session_t *provisioning_session) { + msaf_application_server_state_ref_node_t *next_as_state_ref, *as_state_ref; + ogs_assert(provisioning_session); if (provisioning_session->certificate_map) { free_ogs_hash_context_t fohc = { @@ -697,7 +699,11 @@ msaf_context_provisioning_session_free(msaf_provisioning_session_t *provisioning if (provisioning_session->serviceAccessInformation) OpenAPI_service_access_information_resource_free(provisioning_session->serviceAccessInformation); if (provisioning_session->serviceAccessInformationHash) ogs_free(provisioning_session->serviceAccessInformationHash); - + + ogs_list_for_each_safe(&provisioning_session->application_server_states, next_as_state_ref, as_state_ref) { + ogs_list_remove(&provisioning_session->application_server_states, as_state_ref); + ogs_free(as_state_ref); + } ogs_free(provisioning_session); } From 4aa8aa1947c0b87562d8781a3f2da166c9a4e302 Mon Sep 17 00:00:00 2001 From: David Waring Date: Thu, 23 Mar 2023 18:25:55 +0000 Subject: [PATCH 47/48] Remove traceback output on General Error --- tools/python3/m1_session_cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/python3/m1_session_cli.py b/tools/python3/m1_session_cli.py index 7dfea02..5418233 100755 --- a/tools/python3/m1_session_cli.py +++ b/tools/python3/m1_session_cli.py @@ -789,7 +789,7 @@ async def main(): return 2 except Exception as err: print(f'General failure: {err}') - traceback.print_exc() # add in for debugging + #traceback.print_exc() # add in for debugging return 2 return 0 From 20686e50449d303604b9074e19171dd074b8a4f1 Mon Sep 17 00:00:00 2001 From: David Waring Date: Fri, 24 Mar 2023 10:07:11 +0000 Subject: [PATCH 48/48] Change m1-session tool default m1_address to match the defaults in msaf.yaml. --- tools/python3/m1_session_cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/python3/m1_session_cli.py b/tools/python3/m1_session_cli.py index 5418233..492c246 100755 --- a/tools/python3/m1_session_cli.py +++ b/tools/python3/m1_session_cli.py @@ -112,7 +112,7 @@ class Configuration: [m1-client] log_level = info data_store = %(state_dir)s/m1-client - m1_address = localhost + m1_address = 127.0.0.23 m1_port = 7777 asp_id = external_app_id = please-change-this