diff --git a/.gitmodules b/.gitmodules
index ef40847..9b5c83e 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,3 @@
-[submodule "subprojects/open5gs"]
- path = subprojects/open5gs
- url = https://github.com/open5gs/open5gs.git
[submodule "subprojects/rt-common-shared"]
path = subprojects/rt-common-shared
url = https://github.com/5G-MAG/rt-common-shared.git
diff --git a/README.md b/README.md
index 010f86a..4aa4e52 100644
--- a/README.md
+++ b/README.md
@@ -1,24 +1,24 @@
-# 5GMS Application Function
-
-This repository holds the 5GMS Application Function implementation for the 5G-MAG Reference Tools.
-Note that currently this implementation only supports downlink media streaming.
+
5GMS Application Function
+
+
+
+
+
## Introduction
The 5GMS Application Function (AF) is a Network Function that forms part of the 5G Media Services framework as defined in ETSI TS 126.501.
+Additional information can be found at: https://5g-mag.github.io/Getting-Started/pages/5g-media-streaming/
+
### 5GMS Downlink Application Function
A 5GMSd Application Function (AF), which can be deployed in the 5G Core Network or in an External Data Network, is responsible for managing the 5GMSd System. The AF is a logical function which embodies the control plane aspects of the system, including provisioning, configuration, and reporting, among others. A 5GMSd Application Provider provisions 5GMS functions using a RESTful HTTP-based provisioning interface at reference point M1d. Another RESTful HTTP-based configuration and reporting interface is exposed to UE-based 5GMSd Clients at reference point M5d.
-#### Specifications
-
-A list of specification related to this repository is available in the [Standards Wiki](https://github.com/5G-MAG/Standards/wiki/5G-Downlink-Media-Streaming-Architecture-(5GMSd):-Relevant-Specifications).
-
-#### About the implementation
+### About the implementation
This AF uses the [Open5GS](https://open5gs.org/) framework to implement the network function.
-A list of currently supported features is available [here](https://github.com/5G-MAG/rt-5gms-application-function/wiki/Feature-Matrix).
+A list of currently supported features is available [here](https://5g-mag.github.io/Getting-Started/pages/5g-media-streaming/usage/application-function/features-af.html).
## Install dependencies
@@ -84,11 +84,49 @@ 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.
+Also see the [Configuring the Application Function](https://5g-mag.github.io/Getting-Started/pages/5g-media-streaming/usage/application-function/configuration-5GMSAF.html) 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.
+Follow the [Testing as a Local User](https://5g-mag.github.io/Getting-Started/pages/5g-media-streaming/usage/application-function/installation-local-user-5GMSAF.html) page for setting up a test environment without requiring full
+system installation.
+
+### Testing: M1 Interface
+
+The details of these tests change with different versions of the 5GMSd Application Function.
+
+If you are testing the v1.2.x versions then please visit the [Testing the M1 Interface on v1.2.0](https://5g-mag.github.io/Getting-Started/pages/5g-media-streaming/usage/application-function/testing-m1-v120.html) page.
+
+If you are testing the M1 interface on 5GMSd Application Function v1.3.0 to v1.4.0 then please visit the
+[Testing the M1 Interface on v1.3.0](https://5g-mag.github.io/Getting-Started/pages/5g-media-streaming/usage/application-function/testing-m1-v130.html) page.
+
+For testing the M1 interface on 5GMSd Application Function v1.4.1 or later, then please visit the
+[Testing the M1 Interface on v1.4.1](https://5g-mag.github.io/Getting-Started/pages/5g-media-streaming/usage/application-function/testing-m1-v141.html) page.
+
+### Testing the M3 Interface
+
+Depending on which version of the 5GMSd Application Function you wish to test, the commands to test the interface at reference point M3 change.
+
+If you wish to test 5GMSd Application Function v1.1.x then please see the [Testing the M3 Interface on v1.1.0](https://5g-mag.github.io/Getting-Started/pages/5g-media-streaming/usage/application-function/testing-m3-v110.html) page.
+
+For versions after v1.1.x (i.e. v1.2.0 and above) please use the [Testing the M3 Interface on v1.2.0](https://5g-mag.github.io/Getting-Started/pages/5g-media-streaming/usage/application-function/testing-m3-v120.html) page.
+
+### Testing: M5 Interface
+
+The details of these tests change with different versions of the 5GMSd Application Function.
+
+If you are testing versions up to v1.1.x then please visit the [Testing: M5 Interface on v1.0.0](https://5g-mag.github.io/Getting-Started/pages/5g-media-streaming/usage/application-function/testing-m5-v100.html)
+page.
+
+If you are testing the M5 interface on 5GMSd Application Function v1.2.x please visit the
+[Testing the M5 Interface on v1.2.0](https://5g-mag.github.io/Getting-Started/pages/5g-media-streaming/usage/application-function/testing-m5-v120.html) page.
+
+If you are testing the M5 interface on 5GMSd Application Function v1.3.0 or later please visit the
+[Testing the M5 Interface on v1.3.0](https://5g-mag.github.io/Getting-Started/pages/5g-media-streaming/usage/application-function/testing-m5-v130.html) page.
+
+### Testing with Postman
+
+For detailed instructions on how to use the Postman Collection please refer to this [documentation](https://5g-mag.github.io/Getting-Started/pages/5g-media-streaming/usage/application-function/testing-postman.html).
## Development
@@ -97,6 +135,6 @@ the [Gitflow workflow](https://www.atlassian.com/git/tutorials/comparing-workflo
`development` branch of this project serves as an integration branch for new features. Consequently, please make sure to
switch to the `development` branch before starting the implementation of a new feature.
-## Support
+## Acknowledgements
The reference implementation of the Network Assistance and Dynamic Policies features was funded by the UK Government through the [REASON](https://reason-open-networks.ac.uk/) project.
diff --git a/meson.build b/meson.build
index 45f5451..1ef2911 100644
--- a/meson.build
+++ b/meson.build
@@ -9,16 +9,14 @@
# Meson module fs and its functions like fs.hash_file require atleast meson 0.59.0
project('rt-5gms-application-function', 'c',
- version : '1.4.0',
+ version : '1.4.1',
license : '5G-MAG Public',
- meson_version : '>= 0.59.0',
+ meson_version : '>= 0.63.0',
default_options : [
'c_std=gnu89',
],
)
-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)
svc_consumers_project=subproject('rt-5gc-service-consumers',required:true)
diff --git a/src/5gmsaf/5G_APIs-overrides/TS26512_M5_DynamicPolicies.yaml b/src/5gmsaf/5G_APIs-overrides/TS26512_M5_DynamicPolicies.yaml
new file mode 100644
index 0000000..f62643e
--- /dev/null
+++ b/src/5gmsaf/5G_APIs-overrides/TS26512_M5_DynamicPolicies.yaml
@@ -0,0 +1,161 @@
+openapi: 3.0.0
+info:
+ title: M5_DynamicPolicies
+ version: 2.0.2
+ description: |
+ 5GMS AF M5 Dynamic Policy API
+ © 2023, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC).
+ All rights reserved.
+tags:
+ - name: M5_DynamicPolicies
+ description: '5G Media Streaming: Media Session Handling (M5) APIs: Dynamic Policies'
+externalDocs:
+ description: 'TS 26.512 V17.6.0; 5G Media Streaming (5GMS); Protocols'
+ url: 'https://www.3gpp.org/ftp/Specs/archive/26_series/26.512/'
+servers:
+ - url: '{apiRoot}/3gpp-m5/v2'
+ variables:
+ apiRoot:
+ default: https://example.com
+ description: See 3GPP TS 29.512 clause 6.1.
+paths:
+ /dynamic-policies:
+ post:
+ operationId: createDynamicPolicy
+ summary: 'Create (and optionally upload) a new Dynamic Policy resource'
+ requestBody:
+ description: 'An optional JSON representation of a Dynamic Policy resource'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DynamicPolicy'
+ responses:
+ '201':
+ description: 'Created Dynamic Policy Resource'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DynamicPolicy'
+ headers:
+ Location:
+ description: 'The URL of the newly created Dynamic Policy resource'
+ required: true
+ schema:
+ $ref: 'TS26512_CommonData.yaml#/components/schemas/AbsoluteUrl'
+ '400':
+ description: 'Bad Request'
+ '401':
+ description: 'Unauthorized'
+
+ /dynamic-policies/{dynamicPolicyId}:
+ parameters:
+ - name: dynamicPolicyId
+ description: 'The resource identifier of a Dynamic Policy resource'
+ in: path
+ required: true
+ schema:
+ $ref: 'TS26512_CommonData.yaml#/components/schemas/ResourceId'
+ get:
+ operationId: retrieveDynamicPolicy
+ summary: 'Retrieve an existing Dynamic Policy resource'
+ responses:
+ '200':
+ description: 'Success'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DynamicPolicy'
+ '400':
+ description: 'Bad Request'
+ '401':
+ description: 'Unauthorized'
+ '404':
+ description: 'Not Found'
+ put:
+ operationId: updateDynamicPolicy
+ summary: 'Update an existing Dynamic Policy resource'
+ requestBody:
+ description: 'A replacement JSON representation of a Dynamic Policy resource'
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DynamicPolicy'
+ responses:
+ '400':
+ description: 'Bad Request'
+ '401':
+ description: 'Unauthorized'
+ '404':
+ description: 'Not found'
+ patch:
+ operationId: patchDynamicPolicy
+ summary: 'Patch an existing Dynamic Policy resource'
+ requestBody:
+ description: 'A JSON patch to a Dynamic Policy resource'
+ required: true
+ content:
+ application/merge-patch+json:
+ schema:
+ $ref: '#/components/schemas/DynamicPolicy'
+ application/json-patch+json:
+ schema:
+ $ref: '#/components/schemas/DynamicPolicy'
+ responses:
+ '200':
+ description: 'Patched Dynamic Policy'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DynamicPolicy'
+ '204':
+ description: 'Patched Dynamic Policy'
+ '400':
+ description: 'Bad Request'
+ '401':
+ description: 'Unauthorized'
+ '404':
+ description: 'Not found'
+ delete:
+ operationId: destroyDynamicPolicy
+ summary: 'Destroy an existing Dynamic Policy resource'
+ responses:
+ '204':
+ description: 'Destroyed Dynamic Policy'
+ '400':
+ description: 'Bad Request'
+ '401':
+ description: 'Unauthorized'
+ '404':
+ description: 'Not Found'
+components:
+ schemas:
+ DynamicPolicy:
+ description: "A representation of a Dynamic Policy resource."
+ type: object
+ required:
+ - dynamicPolicyId
+ - policyTemplateId
+ - serviceDataFlowDescriptions
+ - provisioningSessionId
+ properties:
+ dynamicPolicyId:
+ readOnly: true
+ allOf:
+ - $ref: 'TS26512_CommonData.yaml#/components/schemas/ResourceId'
+ policyTemplateId:
+ $ref: 'TS26512_CommonData.yaml#/components/schemas/ResourceId'
+ serviceDataFlowDescriptions:
+ type: array
+ items:
+ $ref: 'TS26512_CommonData.yaml#/components/schemas/ServiceDataFlowDescription'
+ mediaType:
+ $ref: 'TS29514_Npcf_PolicyAuthorization.yaml#/components/schemas/MediaType'
+ provisioningSessionId:
+ $ref: 'TS26512_CommonData.yaml#/components/schemas/ResourceId'
+ qosSpecification:
+ $ref: 'TS26512_CommonData.yaml#/components/schemas/M5QoSSpecification'
+ enforcementMethod:
+ type: string
+ enforcementBitRate:
+ type: integer
diff --git a/src/5gmsaf/app.c b/src/5gmsaf/app.c
index 75f07cd..dfc0e96 100644
--- a/src/5gmsaf/app.c
+++ b/src/5gmsaf/app.c
@@ -1,12 +1,12 @@
/*
-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
+ */
#include "ogs-app.h"
diff --git a/src/5gmsaf/application-server-context.c b/src/5gmsaf/application-server-context.c
index 19e606e..b182400 100644
--- a/src/5gmsaf/application-server-context.c
+++ b/src/5gmsaf/application-server-context.c
@@ -1,12 +1,13 @@
/*
-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)
+ * Authors: Dev Audsin
+ * David Waring
+ * Copyright: (C) 2022-2024 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 "ogs-sbi.h"
@@ -48,7 +49,7 @@ 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){
+ ogs_list_for_each(&msaf_self()->application_server_states, as_state) {
if (as_state->application_server == msaf_as) {
msaf_application_server_state_ref_node_t *as_state_ref;
@@ -90,7 +91,7 @@ msaf_application_server_state_update( msaf_provisioning_session_t *provisioning_
{
msaf_application_server_state_ref_node_t *as_state_ref;
- ogs_list_for_each(&provisioning_session->application_server_states, 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);
@@ -188,11 +189,11 @@ msaf_application_server_add(char *canonical_hostname, char *url_path_prefix_form
void msaf_application_server_state_log(ogs_list_t *list, const char* list_name) {
resource_id_node_t *state_node;
- if(!list || (ogs_list_count(list) == 0)){
+ if (!list || (ogs_list_count(list) == 0)) {
ogs_debug("%s is empty",list_name);
} else{
int i = 1;
- ogs_list_for_each(list, state_node){
+ ogs_list_for_each(list, state_node) {
ogs_debug("%s[%d]: %s\n", list_name, i, state_node->state);
i++;
}
@@ -274,26 +275,26 @@ void next_action_for_application_server(msaf_application_server_state_node_t *as
cJSON_Delete(json);
cJSON_free(data);
- } else if (ogs_list_first(&as_state->delete_content_hosting_configurations) != NULL) {
+ } 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) {
+ } 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){
+ } 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);
char *component = ogs_msprintf("content-hosting-configurations/%s/purge", purge_chc->provisioning_session_id);
- if(purge_chc->purge_regex) {
+ 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, OGS_SBI_HTTP_METHOD_POST, component);
} else {
diff --git a/src/5gmsaf/application-server-context.h b/src/5gmsaf/application-server-context.h
index 9990c75..5427ebe 100644
--- a/src/5gmsaf/application-server-context.h
+++ b/src/5gmsaf/application-server-context.h
@@ -1,12 +1,12 @@
/*
-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_APPLICATION_SERVER_H
#define MSAF_APPLICATION_SERVER_H
diff --git a/src/5gmsaf/certmgr.c b/src/5gmsaf/certmgr.c
index 6a20f3d..90a8074 100644
--- a/src/5gmsaf/certmgr.c
+++ b/src/5gmsaf/certmgr.c
@@ -1,7 +1,8 @@
/*
* License: 5G-MAG Public License (v1.0)
- * Authors: Dev Audsin & David Waring
- * Copyright: (C) 2023 British Broadcasting Corporation
+ * Authors: Dev Audsin
+ * David Waring
+ * Copyright: (C) 2023-2024 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
@@ -41,7 +42,7 @@ int server_cert_delete(const char *certid)
out = ogs_proc_stdout(current);
ogs_assert(out);
- while(fgets(buf, OGS_HUGE_LEN, out)) {
+ while (fgets(buf, OGS_HUGE_LEN, out)) {
printf("%s", buf);
}
ret = ogs_proc_join(current, &out_return_code);
@@ -84,9 +85,9 @@ msaf_certificate_t *server_cert_retrieve(const char *certid)
cert = ogs_calloc(1, 4096);
cert_reserved = 4096;
- while(fgets(buf, OGS_HUGE_LEN, out)) {
+ while (fgets(buf, OGS_HUGE_LEN, out)) {
cert_size += strlen (buf);
- if(cert_size > cert_reserved - 1) {
+ if (cert_size > cert_reserved - 1) {
cert_reserved +=4096;
cert = ogs_realloc(cert,cert_reserved);
}
@@ -98,7 +99,7 @@ msaf_certificate_t *server_cert_retrieve(const char *certid)
ogs_assert(ret == 0);
ogs_free(current);
- if(out_return_code == 0 || out_return_code == 4 || out_return_code == 8){
+ 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);
}
@@ -136,9 +137,9 @@ msaf_certificate_t *server_cert_get_servercert(const char *certid)
cert = ogs_calloc(1, 4096);
cert_reserved = 4096;
- while(fgets(buf, OGS_HUGE_LEN, out)) {
+ while (fgets(buf, OGS_HUGE_LEN, out)) {
cert_size += strlen (buf);
- if(cert_size > cert_reserved - 1) {
+ if (cert_size > cert_reserved - 1) {
cert_reserved +=4096;
cert = ogs_realloc(cert,cert_reserved);
}
@@ -150,7 +151,7 @@ msaf_certificate_t *server_cert_get_servercert(const char *certid)
ogs_assert(ret == 0);
ogs_free(current);
- if(!out_return_code){
+ if (!out_return_code) {
msaf_certificate = msaf_certificate_populate(certid, cert, out_return_code);
ogs_assert(msaf_certificate);
}
@@ -244,9 +245,9 @@ msaf_certificate_t *server_cert_new(const char *operation, const char *common_na
cert = ogs_calloc(1, 4096);
cert_reserved = 4096;
- while(fgets(buf, OGS_HUGE_LEN, out)) {
+ while (fgets(buf, OGS_HUGE_LEN, out)) {
cert_size += strlen (buf);
- if(cert_size > cert_reserved - 1) {
+ if (cert_size > cert_reserved - 1) {
cert_reserved =+ 4096;
cert = ogs_realloc(cert,cert_reserved);
}
@@ -289,7 +290,7 @@ char *check_in_cert_list(const char *canonical_domain_name)
out = ogs_proc_stdout(current);
ogs_assert(out);
- while(fgets(buf, OGS_HUGE_LEN, out)) {
+ while (fgets(buf, OGS_HUGE_LEN, out)) {
ogs_debug("buf=\"%s\", canonical_domain_name=\"%s\"", buf, canonical_domain_name);
if (str_match(buf, canonical_domain_name)) {
diff --git a/src/5gmsaf/certmgr.h b/src/5gmsaf/certmgr.h
index be3e327..9ff9220 100644
--- a/src/5gmsaf/certmgr.h
+++ b/src/5gmsaf/certmgr.h
@@ -1,6 +1,6 @@
/*
* License: 5G-MAG Public License (v1.0)
- * Author: Dev Audsin
+ * Author: Dev Audsin
* Copyright: (C) 2022 British Broadcasting Corporation
*
* For full license terms please see the LICENSE file distributed with this
diff --git a/src/5gmsaf/consumption-report-configuration.c b/src/5gmsaf/consumption-report-configuration.c
index 96cf77b..4ab48da 100644
--- a/src/5gmsaf/consumption-report-configuration.c
+++ b/src/5gmsaf/consumption-report-configuration.c
@@ -1,12 +1,12 @@
/*
-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
-*/
+ * 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"
@@ -81,7 +81,7 @@ bool msaf_consumption_report_configuration_deregister(msaf_provisioning_session_
ogs_free(session->httpMetadata.consumptionReportingConfiguration.hash);
session->httpMetadata.consumptionReportingConfiguration.hash = NULL;
}
-
+
session->httpMetadata.consumptionReportingConfiguration.received = 0;
msaf_sai_cache_clear(session->sai_cache);
@@ -126,7 +126,7 @@ char *msaf_consumption_report_configuration_body(msaf_provisioning_session_t *se
{
cJSON *json;
char *body;
-
+
ogs_assert(session);
if (!session->consumptionReportingConfiguration) return NULL;
diff --git a/src/5gmsaf/consumption-report-configuration.h b/src/5gmsaf/consumption-report-configuration.h
index c3d4d6d..e0f5937 100644
--- a/src/5gmsaf/consumption-report-configuration.h
+++ b/src/5gmsaf/consumption-report-configuration.h
@@ -1,12 +1,12 @@
/*
-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
-*/
+ * 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 MSAF_CONSUMPTION_REPORT_CONFIGURATION_H
#define MSAF_CONSUMPTION_REPORT_CONFIGURATION_H
diff --git a/src/5gmsaf/context.c b/src/5gmsaf/context.c
index b01d23f..a8cab7c 100644
--- a/src/5gmsaf/context.c
+++ b/src/5gmsaf/context.c
@@ -1,12 +1,13 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-Copyright: (C) 2022-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Authors: Dev Audsin
+ * David Waring
+ * Copyright: (C) 2022-2024 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
#include
@@ -106,27 +107,27 @@ void msaf_context_final(void)
if (self->config.server_response_cache_control)
{
- ogs_free(self->config.server_response_cache_control);
+ ogs_free(self->config.server_response_cache_control);
}
-
+
if (self->config.certificateManager)
ogs_free(self->config.certificateManager);
msaf_network_assistance_delivery_boost_free();
- if(self->config.offerNetworkAssistance){
+ if (self->config.offerNetworkAssistance) {
//msaf_na_policy_template_remove_all();
- msaf_network_assistance_session_remove_all_pcf_app_session();
+ msaf_network_assistance_session_remove_all_pcf_app_session();
msaf_network_assistance_session_remove_all();
msaf_pcf_session_remove_all();
- bsf_terminate();
- pcf_service_consumer_final();
- //msaf_network_assistance_session_remove_all();
- //pcf_terminate();
+ bsf_terminate();
+ pcf_service_consumer_final();
+ //msaf_network_assistance_session_remove_all();
+ //pcf_terminate();
}
-
+
msaf_pcf_cache_free(self->pcf_cache);
-
+
if (self->config.data_collection_dir)
ogs_free(self->config.data_collection_dir);
@@ -177,7 +178,7 @@ int msaf_context_parse_config(void)
const char *msaf_key = ogs_yaml_iter_key(&msaf_iter);
ogs_assert(msaf_key);
if (!strcmp(msaf_key, "open5gsIntegration")) {
- self->config.open5gsIntegration_flag = ogs_yaml_iter_bool(&msaf_iter);
+ self->config.open5gsIntegration_flag = ogs_yaml_iter_bool(&msaf_iter);
} else if (!strcmp(msaf_key, "certificateManager")) {
self->config.certificateManager = msaf_strdup(ogs_yaml_iter_value(&msaf_iter));
} else if (!strcmp(msaf_key, "applicationServers")) {
@@ -231,6 +232,7 @@ int msaf_context_parse_config(void)
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 m1_metrics_reporting_response_max_age = SERVER_RESPONSE_MAX_AGE;
int m1_consumption_reporting_response_max_age = SERVER_RESPONSE_MAX_AGE;
int m5_service_access_information_response_max_age = SERVER_RESPONSE_MAX_AGE;
while (ogs_yaml_iter_next(&cc_iter)) {
@@ -244,6 +246,8 @@ int msaf_context_parse_config(void)
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, "m1MetricsReportingConfiguration")){
+ m1_metrics_reporting_response_max_age = ascii_to_long(ogs_yaml_iter_value(&cc_iter));
} else if (!strcmp(cc_key, "m1ConsumptionReportingConfiguration")) {
m1_consumption_reporting_response_max_age = ascii_to_long(ogs_yaml_iter_value(&cc_iter));
} else if (!strcmp(cc_key, "m5ServiceAccessInformation")) {
@@ -252,16 +256,16 @@ 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,
+ m1_server_certificates_response_max_age, m1_content_protocols_response_max_age, m1_metrics_reporting_response_max_age,
m1_consumption_reporting_response_max_age, m5_service_access_information_response_max_age);
-
- } else if ((!strcmp(msaf_key, "sbi") && self->config.open5gsIntegration_flag)) {
+
+ } else if ((!strcmp(msaf_key, "sbi") && self->config.open5gsIntegration_flag)) {
/* handle config in sbi library */
- } else if (!strcmp(msaf_key, "sbi") || !strcmp(msaf_key, "m1") || !strcmp(msaf_key, "m5") || !strcmp(msaf_key, "maf")) {
-
+ } else if (!strcmp(msaf_key, "sbi") || !strcmp(msaf_key, "m1") || !strcmp(msaf_key, "m5") || !strcmp(msaf_key, "maf")) {
+
ogs_list_t list, list6;
ogs_socknode_t *node = NULL, *node6 = NULL;
@@ -273,7 +277,7 @@ int msaf_context_parse_config(void)
const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
int num_of_advertise = 0;
const char *advertise[OGS_MAX_NUM_OF_HOSTNAME];
-
+
uint16_t port = 0;
const char *dev = NULL;
ogs_sockaddr_t *addr = NULL;
@@ -365,10 +369,10 @@ int msaf_context_parse_config(void)
} else
ogs_warn("unknown key `%s`", sbi_key);
}
-
- if (port == 0){
+
+ if (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++) {
@@ -414,12 +418,12 @@ int msaf_context_parse_config(void)
break;
}
}
- if(!matches) {
+ if (!matches) {
server = ogs_sbih1_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);
@@ -436,21 +440,21 @@ int msaf_context_parse_config(void)
}
}
} else if (!strcmp(msaf_key, "m1")) {
- if(self->config.servers[MSAF_SVR_M1].ipv4){
+ if (self->config.servers[MSAF_SVR_M1].ipv4) {
ogs_freeaddrinfo(self->config.servers[MSAF_SVR_M1].ipv4);
self->config.servers[MSAF_SVR_M1].ipv4 = NULL;
}
ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.servers[MSAF_SVR_M1].ipv4, server->node.addr));
self->config.servers[MSAF_SVR_M1].server_v4 = server;
} else if (!strcmp(msaf_key, "m5")) {
- if(self->config.servers[MSAF_SVR_M5].ipv4){
+ if (self->config.servers[MSAF_SVR_M5].ipv4) {
ogs_freeaddrinfo(self->config.servers[MSAF_SVR_M5].ipv4);
self->config.servers[MSAF_SVR_M5].ipv4 = NULL;
}
ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.servers[MSAF_SVR_M5].ipv4, server->node.addr));
self->config.servers[MSAF_SVR_M5].server_v4 = server;
} else if (!strcmp(msaf_key, "maf")) {
- if(self->config.servers[MSAF_SVR_MSAF].ipv4){
+ if (self->config.servers[MSAF_SVR_MSAF].ipv4) {
ogs_freeaddrinfo(self->config.servers[MSAF_SVR_MSAF].ipv4);
self->config.servers[MSAF_SVR_MSAF].ipv4 = NULL;
}
@@ -470,11 +474,11 @@ int msaf_context_parse_config(void)
break;
}
}
- if(!matches) {
+ if (!matches) {
server = ogs_sbih1_server_add(
node->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);
@@ -491,21 +495,21 @@ int msaf_context_parse_config(void)
}
}
} else if (!strcmp(msaf_key, "m1")) {
- if(self->config.servers[MSAF_SVR_M1].ipv6){
+ if (self->config.servers[MSAF_SVR_M1].ipv6) {
ogs_freeaddrinfo(self->config.servers[MSAF_SVR_M1].ipv6);
self->config.servers[MSAF_SVR_M1].ipv6 = NULL;
}
ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.servers[MSAF_SVR_M1].ipv6, server->node.addr));
self->config.servers[MSAF_SVR_M1].server_v6 = server;
} else if (!strcmp(msaf_key, "m5")) {
- if(self->config.servers[MSAF_SVR_M5].ipv6){
+ if (self->config.servers[MSAF_SVR_M5].ipv6) {
ogs_freeaddrinfo(self->config.servers[MSAF_SVR_M5].ipv6);
self->config.servers[MSAF_SVR_M5].ipv6 = NULL;
}
ogs_assert(OGS_OK == ogs_copyaddrinfo(&self->config.servers[MSAF_SVR_M5].ipv6, server->node.addr));
self->config.servers[MSAF_SVR_M5].server_v6 = server;
} else if (!strcmp(msaf_key, "maf")) {
- if(self->config.servers[MSAF_SVR_MSAF].ipv6){
+ if (self->config.servers[MSAF_SVR_MSAF].ipv6) {
ogs_freeaddrinfo(self->config.servers[MSAF_SVR_MSAF].ipv6);
self->config.servers[MSAF_SVR_MSAF].ipv6 = NULL;
}
@@ -521,7 +525,7 @@ int msaf_context_parse_config(void)
ogs_socknode_remove_all(&list6);
} while (ogs_yaml_iter_type(&sbi_array) == YAML_SEQUENCE_NODE);
-
+
/* handle config in sbi library */
} else if (!strcmp(msaf_key, "service_name")) {
/* handle config in sbi library */
@@ -531,7 +535,7 @@ int msaf_context_parse_config(void)
self->config.data_collection_dir = msaf_strdup(ogs_yaml_iter_value(&msaf_iter));
} else if (!strcmp(msaf_key, "offerNetworkAssistance")) {
self->config.offerNetworkAssistance = ogs_yaml_iter_bool(&msaf_iter);
- msaf_context_network_assistance_session_init();
+ msaf_context_network_assistance_session_init();
} else if (!strcmp(msaf_key, "networkAssistance")) {
ogs_yaml_iter_t na_iter, na_array;
ogs_yaml_iter_recurse(&msaf_iter, &na_array);
@@ -545,17 +549,17 @@ int msaf_context_parse_config(void)
break;
} else
ogs_assert_if_reached();
-
- //int delivery_boost_min_dl_bit_rate;
- uint64_t delivery_boost_min_dl_bit_rate;
- int delivery_boost_period;
+
+ //int delivery_boost_min_dl_bit_rate;
+ uint64_t delivery_boost_min_dl_bit_rate;
+ int delivery_boost_period;
while (ogs_yaml_iter_next(&na_iter)) {
const char *na_key = ogs_yaml_iter_key(&na_iter);
ogs_assert(na_key);
if (!strcmp(na_key, "deliveryBoost")) {
- ogs_info("deliveryBoost");
- ogs_yaml_iter_t db_iter, db_array;
+ ogs_info("deliveryBoost");
+ ogs_yaml_iter_t db_iter, db_array;
ogs_yaml_iter_recurse(&na_iter, &db_array);
if (ogs_yaml_iter_type(&db_array) == YAML_MAPPING_NODE) {
memcpy(&db_iter, &db_array, sizeof(ogs_yaml_iter_t));
@@ -573,28 +577,28 @@ int msaf_context_parse_config(void)
ogs_assert(db_key);
if (!strcmp(db_key, "minDlBitRate")) {
ogs_info("deliveryBoost.minDlBitRate");
-
- delivery_boost_min_dl_bit_rate = ogs_sbi_bitrate_from_string((char*)ogs_yaml_iter_value(&db_iter)); /* cast safe as ogs_sbi_bitrate_from_string doesn't alter the string */
-
- ogs_info("delivery_boost_min_dl_bit_rate: %ld", delivery_boost_min_dl_bit_rate);
- /*
- delivery_boost_min_dl_bit_rate = atoi(ogs_yaml_iter_value(&db_iter));
- ogs_info("delivery_boost_min_dl_bit_rate: %d", delivery_boost_min_dl_bit_rate);
- */
+
+ delivery_boost_min_dl_bit_rate = ogs_sbi_bitrate_from_string((char*)ogs_yaml_iter_value(&db_iter)); /* cast safe as ogs_sbi_bitrate_from_string doesn't alter the string */
+
+ ogs_info("delivery_boost_min_dl_bit_rate: %ld", delivery_boost_min_dl_bit_rate);
+ /*
+ delivery_boost_min_dl_bit_rate = atoi(ogs_yaml_iter_value(&db_iter));
+ ogs_info("delivery_boost_min_dl_bit_rate: %d", delivery_boost_min_dl_bit_rate);
+ */
}
- if (!strcmp(db_key, "boostPeriod")) {
+ if (!strcmp(db_key, "boostPeriod")) {
ogs_info("deliveryBoost.boostPeriod");
delivery_boost_period = atoi(ogs_yaml_iter_value(&db_iter));
- ogs_info("delivery_boost_period: %d", delivery_boost_period);
+ ogs_info("delivery_boost_period: %d", delivery_boost_period);
}
}
- msaf_network_assistance_delivery_boost_set_from_config( delivery_boost_min_dl_bit_rate, delivery_boost_period);
+ msaf_network_assistance_delivery_boost_set_from_config( delivery_boost_min_dl_bit_rate, delivery_boost_period);
}
}
}
-
- else {
+
+ else {
ogs_warn("unknown key `%s`", msaf_key);
}
}
@@ -634,11 +638,11 @@ static void msaf_context_network_assistance_session_init(void)
ogs_list_init(&self->delete_pcf_app_sessions);
}
-static int check_for_network_assistance_support(void){
+static int check_for_network_assistance_support(void) {
- if(self->config.offerNetworkAssistance && !self->config.open5gsIntegration_flag) {
+ if (self->config.offerNetworkAssistance && !self->config.open5gsIntegration_flag) {
ogs_info("msaf.open5gsIntegration must be true if msaf.offerNetworkAssistance is true. For network assistance set both \"offerNetworkAssistance: true\" and \"open5gsIntegration: true\" in the configuration file");
- return OGS_ERROR;
+ return OGS_ERROR;
}
return OGS_OK;
@@ -658,18 +662,18 @@ static void msaf_context_application_server_state_certificates_remove_all(void)
resource_id_node_t *delete_certificate, *node = NULL;
ogs_debug("Removing all upload certificates");
- ogs_list_for_each_safe(&as_state->upload_certificates, next_node, upload_certificate){
+ ogs_list_for_each_safe(&as_state->upload_certificates, next_node, upload_certificate) {
if (upload_certificate->state)
ogs_free(upload_certificate->state);
ogs_list_remove(&as_state->upload_certificates, upload_certificate);
- if(upload_certificate)
+ if (upload_certificate)
ogs_free(upload_certificate);
}
if (as_state->current_certificates) {
ogs_debug("Removing all current certificates");
- ogs_list_for_each_safe(as_state->current_certificates, next, certificate){
+ ogs_list_for_each_safe(as_state->current_certificates, next, certificate) {
if (certificate->state)
ogs_free(certificate->state);
ogs_list_remove(as_state->current_certificates, certificate);
@@ -680,7 +684,7 @@ static void msaf_context_application_server_state_certificates_remove_all(void)
}
}
- ogs_list_for_each_safe(&as_state->delete_certificates, node, delete_certificate){
+ ogs_list_for_each_safe(&as_state->delete_certificates, node, delete_certificate) {
if (delete_certificate->state)
ogs_free(delete_certificate->state);
ogs_list_remove(&as_state->delete_certificates, delete_certificate);
@@ -699,8 +703,8 @@ static void msaf_context_application_server_state_content_hosting_configuration_
resource_id_node_t *upload_content_hosting_configuration = NULL;
resource_id_node_t *delete_content_hosting_configuration, *node = NULL;
- ogs_list_for_each_safe(&as_state->upload_content_hosting_configurations, next, upload_content_hosting_configuration){
- if(upload_content_hosting_configuration->state)
+ ogs_list_for_each_safe(&as_state->upload_content_hosting_configurations, next, upload_content_hosting_configuration) {
+ if (upload_content_hosting_configuration->state)
ogs_free(upload_content_hosting_configuration->state);
ogs_list_remove(&as_state->upload_content_hosting_configurations, upload_content_hosting_configuration);
ogs_free(upload_content_hosting_configuration);
@@ -708,7 +712,7 @@ static void msaf_context_application_server_state_content_hosting_configuration_
}
if (as_state->current_content_hosting_configurations) {
- ogs_list_for_each_safe(as_state->current_content_hosting_configurations, next, content_hosting_configuration){
+ ogs_list_for_each_safe(as_state->current_content_hosting_configurations, next, content_hosting_configuration) {
ogs_free(content_hosting_configuration->state);
ogs_list_remove(as_state->current_content_hosting_configurations, content_hosting_configuration);
ogs_free(content_hosting_configuration);
@@ -716,7 +720,7 @@ static void msaf_context_application_server_state_content_hosting_configuration_
}
}
- ogs_list_for_each_safe(&as_state->delete_content_hosting_configurations, node, delete_content_hosting_configuration){
+ ogs_list_for_each_safe(&as_state->delete_content_hosting_configurations, node, delete_content_hosting_configuration) {
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);
@@ -732,7 +736,7 @@ static void msaf_context_application_server_state_assigned_provisioning_sessions
assigned_provisioning_sessions_node_t *provisioning_session_resource;
assigned_provisioning_sessions_node_t *provisioning_session_node = NULL;
- ogs_list_for_each_safe(&as_state->assigned_provisioning_sessions, provisioning_session_node, provisioning_session_resource){
+ ogs_list_for_each_safe(&as_state->assigned_provisioning_sessions, provisioning_session_node, provisioning_session_resource) {
ogs_list_remove(&as_state->assigned_provisioning_sessions, provisioning_session_resource);
ogs_free(provisioning_session_resource);
@@ -747,19 +751,19 @@ static void msaf_context_application_server_state_remove_all(void) {
ogs_list_for_each_safe(&self->application_server_states, as_state_node, as_state) {
ogs_list_remove(&self->application_server_states, as_state);
- if(as_state->current_certificates)
+ if (as_state->current_certificates)
ogs_free(as_state->current_certificates);
- if(as_state->current_content_hosting_configurations)
+ if (as_state->current_content_hosting_configurations)
ogs_free(as_state->current_content_hosting_configurations);
ogs_free (as_state);
}
}
-static void msaf_context_server_sockaddr_remove(void){
+static void msaf_context_server_sockaddr_remove(void) {
int i;
for (i=0; iconfig.servers[i].ipv4) ogs_freeaddrinfo(self->config.servers[i].ipv4);
- if(self->config.servers[i].ipv6) ogs_freeaddrinfo(self->config.servers[i].ipv6);
+ if (self->config.servers[i].ipv4) ogs_freeaddrinfo(self->config.servers[i].ipv4);
+ if (self->config.servers[i].ipv6) ogs_freeaddrinfo(self->config.servers[i].ipv6);
}
}
@@ -795,7 +799,7 @@ msaf_context_provisioning_session_free(msaf_provisioning_session_t *provisioning
static void
safe_ogs_free(void *memory)
{
- if(memory)
+ if (memory)
ogs_free(memory);
}
@@ -804,8 +808,8 @@ int msaf_context_server_name_set(void) {
ogs_sbi_server_t *server = NULL;
ogs_list_for_each(&ogs_sbi_self()->server_list, server) {
-
- ogs_sockaddr_t *advertise = NULL;
+
+ ogs_sockaddr_t *advertise = NULL;
int res = 0;
advertise = server->advertise;
@@ -815,7 +819,7 @@ int msaf_context_server_name_set(void) {
res = getnameinfo(&advertise->sa, ogs_sockaddr_len(advertise),
self->server_name, sizeof(self->server_name),
NULL, 0, NI_NAMEREQD);
- if(res) {
+ if (res) {
ogs_debug("Unable to retrieve server name: %d\n", res);
continue;
} else {
diff --git a/src/5gmsaf/context.h b/src/5gmsaf/context.h
index b4a41b9..3e574fa 100644
--- a/src/5gmsaf/context.h
+++ b/src/5gmsaf/context.h
@@ -1,12 +1,12 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-Copyright: (C) 2022-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Author: Dev Audsin
+ * Copyright: (C) 2022-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 MSAF_CONTEXT_H
#define MSAF_CONTEXT_H
diff --git a/src/5gmsaf/data-collection.c b/src/5gmsaf/data-collection.c
index d35bce8..ee685b8 100644
--- a/src/5gmsaf/data-collection.c
+++ b/src/5gmsaf/data-collection.c
@@ -1,11 +1,11 @@
/*
-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
+ * License: 5G-MAG Public License (v1.0)
+ * Author: David Waring
+ * Copyright: (C) 2023-2024 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
@@ -19,6 +19,7 @@ program. If this file is missing then the license can be retrieved from
#include "ogs-core.h"
#include "context.h"
+#include "utilities.h"
#include "data-collection.h"
@@ -41,7 +42,7 @@ bool msaf_data_collection_store(const char *provisioning_session_id, const char
size_t body_len;
fd = open_data_store_file(provisioning_session_id, report_class, client_id, session_id, report_time, format);
-
+
if (fd < 0) {
return false;
}
@@ -73,7 +74,7 @@ static bool ensure_directory(const char *path)
}
} else {
/* path doesn't exist so ensure parent directory is present and try to create wanted directory */
- char *path_copy = ogs_strdup(path);
+ char *path_copy = msaf_strdup(path);
if (ensure_directory(dirname(path_copy)) && !mkdir(path, 0755)) {
ret = true;
}
diff --git a/src/5gmsaf/data-collection.h b/src/5gmsaf/data-collection.h
index c47aa1a..cd6e38e 100644
--- a/src/5gmsaf/data-collection.h
+++ b/src/5gmsaf/data-collection.h
@@ -1,11 +1,11 @@
/*
-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
+ * 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 DATA_COLLECTION_H
diff --git a/src/5gmsaf/dynamic-policy.c b/src/5gmsaf/dynamic-policy.c
index a625259..2fa6496 100644
--- a/src/5gmsaf/dynamic-policy.c
+++ b/src/5gmsaf/dynamic-policy.c
@@ -1,12 +1,13 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Authors: Dev Audsin
+ * David Waring
+ * Copyright: (C) 2023-2024 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 "utilities.h"
#include "dynamic-policy.h"
@@ -33,7 +34,7 @@ typedef struct app_session_change_cb_data_s {
static msaf_dynamic_policy_t *msaf_dynamic_policy_init(void);
static void msaf_dynamic_policy_remove(msaf_dynamic_policy_t *msaf_dynamic_policy);
static void ue_connection_details_free(ue_network_identifier_t *ue_connection);
-static char *set_max_bit_rate_compliant_with_policy_template(char *policy_template_m1_qos_bit_rate, char *m5_qos_bit_rate);
+static char *set_max_bit_rate_compliant_with_policy_template(char *policy_template_m1_qos_bit_rate, char *m5_qos_bit_rate);
static int calculate_max_bit_rate_for_enforcement(char *policy_template_m1_qos_bit_rate, char *m5_qos_bit_rate);
static bool app_session_change_callback(pcf_app_session_t *app_session, void *user_data);
static bool app_session_notification_callback(pcf_app_session_t *app_session, const OpenAPI_events_notification_t *notifications, void *user_data);
@@ -85,13 +86,13 @@ int msaf_dynamic_policy_create(cJSON *dynamicPolicy, msaf_event_t *e)
dynamic_policy = msaf_api_dynamic_policy_parseRequestFromJSON(dynamicPolicy, &reason);
- if(!dynamic_policy) {
- ogs_error("Dynamic Policy Badly formed JSON: [%s]", reason);
+ if (!dynamic_policy) {
+ ogs_error("Dynamic Policy Badly formed JSON: [%s]", reason);
return 0;
}
dyn_policy = msaf_dynamic_policy_init();
- if(!dyn_policy) return 0;
+ if (!dyn_policy) return 0;
dyn_policy->DynamicPolicy = dynamic_policy;
ogs_assert(dyn_policy->DynamicPolicy);
@@ -111,18 +112,18 @@ int msaf_dynamic_policy_create(cJSON *dynamicPolicy, msaf_event_t *e)
service_data_flow_description = (msaf_api_service_data_flow_description_t *)node->data;
/* Not Implemented Yet */
- if(service_data_flow_description->domain_name) {
- ogs_error("Service Data Flow Descriptions specified using a domain name are not yet supported by this implementation");
+ if (service_data_flow_description->domain_name) {
+ ogs_error("Service Data Flow Descriptions specified using a domain name are not yet supported by this implementation");
msaf_dynamic_policy_remove(dyn_policy);
- return 0;
- }
+ return 0;
+ }
/* Validate SDF */
- if (service_data_flow_description->flow_description && service_data_flow_description->domain_name) {
- ogs_error("Validation of service data flow description failed: Only one of flowDescription or domainName may be present");
+ if (service_data_flow_description->flow_description && service_data_flow_description->domain_name) {
+ ogs_error("Validation of service data flow description failed: Only one of flowDescription or domainName may be present");
msaf_dynamic_policy_remove(dyn_policy);
return 0;
- }
+ }
if (!service_data_flow_description->flow_description && !service_data_flow_description->domain_name) {
ogs_error("Validation of service data flow description failed: flowDescription or domainName must be present");
@@ -130,7 +131,7 @@ int msaf_dynamic_policy_create(cJSON *dynamicPolicy, msaf_event_t *e)
return 0;
}
- if (service_data_flow_description->flow_description) {
+ if (service_data_flow_description->flow_description) {
if (!service_data_flow_description->flow_description->direction) {
ogs_error("Mandatory direction property missing");
@@ -181,8 +182,8 @@ int msaf_dynamic_policy_create(cJSON *dynamicPolicy, msaf_event_t *e)
return 0;
}
- msaf_policy_template = msaf_provisioning_session_get_policy_template_by_id(dynamic_policy->provisioning_session_id, dynamic_policy->policy_template_id);
- if (!msaf_policy_template) {
+ msaf_policy_template = msaf_provisioning_session_get_policy_template_by_id(dynamic_policy->provisioning_session_id, dynamic_policy->policy_template_id);
+ if (!msaf_policy_template) {
ogs_error("Cannot find policy template %s in provisioning session %s", dynamic_policy->policy_template_id, dynamic_policy->provisioning_session_id);
msaf_dynamic_policy_remove(dyn_policy);
return 0;
@@ -193,16 +194,16 @@ int msaf_dynamic_policy_create(cJSON *dynamicPolicy, msaf_event_t *e)
ogs_error("Unable to convert policy to MediaComponent");
msaf_dynamic_policy_remove(dyn_policy);
return 0;
- }
+ }
dynamic_policy_set_enforcement_bit_rate(msaf_policy_template, dynamic_policy);
- /*
- dynamic_policy->is_enforcement_bit_rate = true;
- if (!dynamic_policy->qos_specification) {
- dynamic_policy->enforcement_bit_rate = ogs_sbi_bitrate_from_string(msaf_policy_template->policy_template->qo_s_specification->max_auth_btr_dl?msaf_policy_template->policy_template->qo_s_specification->max_auth_btr_dl: msaf_policy_template->policy_template->qo_s_specification->max_btr_dl);
+ /*
+ dynamic_policy->is_enforcement_bit_rate = true;
+ if (!dynamic_policy->qos_specification) {
+ dynamic_policy->enforcement_bit_rate = ogs_sbi_bitrate_from_string(msaf_policy_template->policy_template->qo_s_specification->max_auth_btr_dl?msaf_policy_template->policy_template->qo_s_specification->max_auth_btr_dl: msaf_policy_template->policy_template->qo_s_specification->max_btr_dl);
} else {
- dynamic_policy->enforcement_bit_rate = calculate_max_bit_rate_for_enforcement(msaf_policy_template->policy_template->qo_s_specification->max_auth_btr_dl?msaf_policy_template->policy_template->qo_s_specification->max_auth_btr_dl: msaf_policy_template->policy_template->qo_s_specification->max_btr_dl, dynamic_policy->qos_specification->mar_bw_dl_bit_rate);
+ dynamic_policy->enforcement_bit_rate = calculate_max_bit_rate_for_enforcement(msaf_policy_template->policy_template->qo_s_specification->max_auth_btr_dl?msaf_policy_template->policy_template->qo_s_specification->max_auth_btr_dl: msaf_policy_template->policy_template->qo_s_specification->max_btr_dl, dynamic_policy->qos_specification->mar_bw_dl_bit_rate);
}
- */
+ */
pcf_address = msaf_pcf_cache_find(msaf_self()->pcf_cache, ue_connection->address);
if (pcf_address) {
@@ -212,7 +213,7 @@ int msaf_dynamic_policy_create(cJSON *dynamicPolicy, msaf_event_t *e)
}
ue_connection_details_free(ue_connection);
}
- }
+ }
} else {
ogs_error("Must have a serviceDataFlowDescriptions");
msaf_dynamic_policy_remove(dyn_policy);
@@ -230,30 +231,30 @@ int msaf_dynamic_policy_update_pcf(msaf_dynamic_policy_t *msaf_dynamic_policy, m
ogs_assert(dynamic_policy);
msaf_policy_template = msaf_provisioning_session_get_policy_template_by_id(dynamic_policy->provisioning_session_id, dynamic_policy->policy_template_id);
- if(!msaf_policy_template) return 0;
+ if (!msaf_policy_template) return 0;
dynamic_policy_set_enforcement_bit_rate(msaf_policy_template, dynamic_policy);
/*
- if(!dynamic_policy->qos_specification) {
+ if (!dynamic_policy->qos_specification) {
dynamic_policy->enforcement_bit_rate = ogs_sbi_bitrate_from_string(msaf_policy_template->policy_template->qo_s_specification->max_btr_dl);
} else {
dynamic_policy->enforcement_bit_rate = calculate_max_bit_rate_for_enforcement(msaf_policy_template->policy_template->qo_s_specification->max_btr_dl, dynamic_policy->qos_specification->mar_bw_dl_bit_rate);
- }
- */
+ }
+ */
media_comps = update_media_component(msaf_policy_template->policy_template->qo_s_specification, dynamic_policy->qos_specification, dynamic_policy->media_type?dynamic_policy->media_type: OpenAPI_media_type_VIDEO);
if (msaf_dynamic_policy->pcf_app_session) {
- if(!pcf_session_update_app_session(msaf_dynamic_policy->pcf_app_session, media_comps)) {
+ if (!pcf_session_update_app_session(msaf_dynamic_policy->pcf_app_session, media_comps)) {
ogs_error("Unable to send dynamic policy update request to the PCF");
- return 0;
+ return 0;
}
} else {
ogs_error("The dynamic policy has no associated App Session");
- return 0;
+ return 0;
}
update_dynamic_policy_context(msaf_dynamic_policy, dynamic_policy);
@@ -266,8 +267,8 @@ cJSON *msaf_dynamic_policy_get_json(const char *dynamic_policy_id)
msaf_dynamic_policy_t *dynamic_policy = NULL;
dynamic_policy = msaf_dynamic_policy_find_by_dynamicPolicyId(dynamic_policy_id);
-
- if(dynamic_policy)
+
+ if (dynamic_policy)
return msaf_api_dynamic_policy_convertResponseToJSON(dynamic_policy->DynamicPolicy);
return NULL;
@@ -282,48 +283,48 @@ msaf_dynamic_policy_find_by_dynamicPolicyId(const char *dynamicPolicyId)
void msaf_dynamic_policy_delete_by_id(const char *dynamic_policy_id, msaf_event_t *delete_event)
{
-
+
msaf_dynamic_policy_t *msaf_dynamic_policy;
if (!msaf_self()->dynamic_policies) return;
msaf_dynamic_policy = msaf_dynamic_policy_find_by_dynamicPolicyId(dynamic_policy_id);
- if(msaf_dynamic_policy) {
+ if (msaf_dynamic_policy) {
add_delete_event_metadata_to_dynamic_policy_context(msaf_dynamic_policy, delete_event);
pcf_app_session_free(msaf_dynamic_policy->pcf_app_session);
}
-}
+}
void msaf_context_dynamic_policy_free(msaf_dynamic_policy_t *dynamic_policy) {
- msaf_dynamic_policy_remove(dynamic_policy);
+ msaf_dynamic_policy_remove(dynamic_policy);
}
/*Private functions */
-static msaf_dynamic_policy_t *msaf_dynamic_policy_init(void){
+static msaf_dynamic_policy_t *msaf_dynamic_policy_init(void) {
msaf_dynamic_policy_t *dyn_policy;
dyn_policy = ogs_calloc(1, sizeof(msaf_dynamic_policy_t));
- if(!dyn_policy) return NULL;
+ if (!dyn_policy) return NULL;
return dyn_policy;
}
static void update_dynamic_policy_context(msaf_dynamic_policy_t *msaf_dynamic_policy, msaf_api_dynamic_policy_t *dynamic_policy) {
-
- cJSON *dynamic_policy_json;
+
+ cJSON *dynamic_policy_json;
char *dynamic_policy_to_hash;
-
+
dynamic_policy_json = msaf_api_dynamic_policy_convertResponseToJSON(dynamic_policy);
- if(dynamic_policy_json) {
+ if (dynamic_policy_json) {
dynamic_policy_to_hash = cJSON_Print(dynamic_policy_json);
- if(msaf_dynamic_policy->hash) ogs_free(msaf_dynamic_policy->hash);
+ if (msaf_dynamic_policy->hash) ogs_free(msaf_dynamic_policy->hash);
msaf_dynamic_policy->hash = calculate_hash(dynamic_policy_to_hash);
msaf_dynamic_policy->dynamic_policy_created = time(NULL);
- if(msaf_dynamic_policy->DynamicPolicy)
+ if (msaf_dynamic_policy->DynamicPolicy)
msaf_api_dynamic_policy_free(msaf_dynamic_policy->DynamicPolicy);
msaf_dynamic_policy->DynamicPolicy = dynamic_policy;
@@ -331,7 +332,7 @@ static void update_dynamic_policy_context(msaf_dynamic_policy_t *msaf_dynamic_po
cJSON_free(dynamic_policy_to_hash);
} else {
- ogs_error("Error converting the Dynamic Policy to JSON");
+ ogs_error("Error converting the Dynamic Policy to JSON");
}
}
@@ -347,32 +348,32 @@ static OpenAPI_list_t *populate_media_component(msaf_api_m1_qo_s_specification_t
MediaComponentList = OpenAPI_list_create();
ogs_assert(MediaComponentList);
- if(!requested_qos) {
- if(m1_qos->max_auth_btr_dl) {
+ if (!requested_qos) {
+ if (m1_qos->max_auth_btr_dl) {
mar_bw_dl_bit_rate = m1_qos->max_auth_btr_dl;
- } else if(m1_qos->max_btr_dl) {
+ } else if (m1_qos->max_btr_dl) {
mar_bw_dl_bit_rate = m1_qos->max_btr_dl;
- }
+ }
- if(m1_qos->max_auth_btr_ul) {
+ if (m1_qos->max_auth_btr_ul) {
mar_bw_ul_bit_rate = m1_qos->max_auth_btr_ul;
- } else if(m1_qos->max_btr_ul) {
+ } else if (m1_qos->max_btr_ul) {
mar_bw_ul_bit_rate = m1_qos->max_btr_ul;
- }
+ }
} else {
-
- if(m1_qos->max_auth_btr_dl) {
+
+ if (m1_qos->max_auth_btr_dl) {
mar_bw_dl_bit_rate = set_max_bit_rate_compliant_with_policy_template(m1_qos->max_auth_btr_dl, requested_qos->mar_bw_dl_bit_rate);
- } else if(m1_qos->max_btr_dl) {
+ } else if (m1_qos->max_btr_dl) {
mar_bw_dl_bit_rate = set_max_bit_rate_compliant_with_policy_template(m1_qos->max_btr_dl, requested_qos->mar_bw_dl_bit_rate);
- }
-
- if(m1_qos->max_auth_btr_ul) {
+ }
+
+ if (m1_qos->max_auth_btr_ul) {
mar_bw_ul_bit_rate = set_max_bit_rate_compliant_with_policy_template(m1_qos->max_auth_btr_ul, requested_qos->mar_bw_ul_bit_rate);
- } else if(m1_qos->max_btr_ul) {
+ } else if (m1_qos->max_btr_ul) {
mar_bw_ul_bit_rate = set_max_bit_rate_compliant_with_policy_template(m1_qos->max_btr_ul, requested_qos->mar_bw_ul_bit_rate);
- }
+ }
}
if (flow_description->src_ip || flow_description->src_port !=0 || flow_description->protocol != IPPROTO_IP ||
@@ -424,7 +425,7 @@ static OpenAPI_list_t *populate_media_component(msaf_api_m1_qo_s_specification_t
ogs_free(ue_port);
ogs_free(remote_port);
- media_sub_comp = OpenAPI_media_sub_component_create(OpenAPI_af_sig_protocol_NULL,
+ media_sub_comp = OpenAPI_media_sub_component_create(OpenAPI_af_sig_protocol_NULL,
NULL, 0, flow_descs, OpenAPI_flow_status_ENABLED,
mar_bw_dl_bit_rate,
mar_bw_ul_bit_rate,
@@ -472,30 +473,30 @@ static OpenAPI_list_t *update_media_component(msaf_api_m1_qo_s_specification_t *
media_comps = OpenAPI_list_create();
ogs_assert(media_comps);
- if(!requested_qos) {
- if(m1_qos->max_auth_btr_dl) {
+ if (!requested_qos) {
+ if (m1_qos->max_auth_btr_dl) {
mar_bw_dl_bit_rate = m1_qos->max_auth_btr_dl;
- } else if(m1_qos->max_btr_dl) {
+ } else if (m1_qos->max_btr_dl) {
mar_bw_dl_bit_rate = m1_qos->max_btr_dl;
}
- if(m1_qos->max_auth_btr_ul) {
+ if (m1_qos->max_auth_btr_ul) {
mar_bw_ul_bit_rate = m1_qos->max_auth_btr_ul;
- } else if(m1_qos->max_btr_ul) {
+ } else if (m1_qos->max_btr_ul) {
mar_bw_ul_bit_rate = m1_qos->max_btr_ul;
}
} else {
- if(m1_qos->max_auth_btr_dl) {
+ if (m1_qos->max_auth_btr_dl) {
mar_bw_dl_bit_rate = set_max_bit_rate_compliant_with_policy_template(m1_qos->max_auth_btr_dl, requested_qos->mar_bw_dl_bit_rate);
- } else if(m1_qos->max_btr_dl) {
+ } else if (m1_qos->max_btr_dl) {
mar_bw_dl_bit_rate = set_max_bit_rate_compliant_with_policy_template(m1_qos->max_btr_dl, requested_qos->mar_bw_dl_bit_rate);
}
- if(m1_qos->max_auth_btr_ul) {
+ if (m1_qos->max_auth_btr_ul) {
mar_bw_ul_bit_rate = set_max_bit_rate_compliant_with_policy_template(m1_qos->max_auth_btr_ul, requested_qos->mar_bw_ul_bit_rate);
- } else if(m1_qos->max_btr_ul) {
+ } else if (m1_qos->max_btr_ul) {
mar_bw_ul_bit_rate = set_max_bit_rate_compliant_with_policy_template(m1_qos->max_btr_ul, requested_qos->mar_bw_ul_bit_rate);
}
}
@@ -567,9 +568,9 @@ static char *set_max_bit_rate_compliant_with_policy_template(char *policy_templa
qos_bit_rate_m5 = ogs_sbi_bitrate_from_string(m5_qos_bit_rate);
qos_bit_rate_m1 = ogs_sbi_bitrate_from_string(policy_template_m1_qos_bit_rate);
- if(qos_bit_rate_m5 > qos_bit_rate_m1)
+ if (qos_bit_rate_m5 > qos_bit_rate_m1)
return policy_template_m1_qos_bit_rate;
- return m5_qos_bit_rate;
+ return m5_qos_bit_rate;
}
static int calculate_max_bit_rate_for_enforcement(char *policy_template_m1_qos_bit_rate, char *m5_qos_bit_rate) {
@@ -578,7 +579,7 @@ static int calculate_max_bit_rate_for_enforcement(char *policy_template_m1_qos_b
qos_bit_rate_m5 = ogs_sbi_bitrate_from_string(m5_qos_bit_rate);
qos_bit_rate_m1 = ogs_sbi_bitrate_from_string(policy_template_m1_qos_bit_rate);
- if(qos_bit_rate_m5 > qos_bit_rate_m1)
+ if (qos_bit_rate_m5 > qos_bit_rate_m1)
return qos_bit_rate_m1;
return qos_bit_rate_m5;
}
@@ -587,7 +588,7 @@ static void dynamic_policy_set_enforcement_bit_rate(msaf_policy_template_node_t
{
dynamic_policy->is_enforcement_bit_rate = true;
- if(!dynamic_policy->qos_specification) {
+ if (!dynamic_policy->qos_specification) {
dynamic_policy->enforcement_bit_rate = ogs_sbi_bitrate_from_string(msaf_policy_template->policy_template->qo_s_specification->max_auth_btr_dl?msaf_policy_template->policy_template->qo_s_specification->max_auth_btr_dl: msaf_policy_template->policy_template->qo_s_specification->max_btr_dl);
} else {
dynamic_policy->enforcement_bit_rate = calculate_max_bit_rate_for_enforcement(msaf_policy_template->policy_template->qo_s_specification->max_auth_btr_dl?msaf_policy_template->policy_template->qo_s_specification->max_auth_btr_dl: msaf_policy_template->policy_template->qo_s_specification->max_btr_dl, dynamic_policy->qos_specification->mar_bw_dl_bit_rate);
@@ -602,9 +603,9 @@ static void create_dynamic_policy_app_session(const ogs_sockaddr_t *pcf_address,
ue_network_identifier_t *ue_net = NULL;
pcf_session = msaf_pcf_session_new(pcf_address);
-
- if(!pcf_session) {
- ogs_assert(true == nf_server_send_error(dynamic_policy->metadata->create_event->h.sbi.data, 401, 0, dynamic_policy->metadata->create_event->message, "Failed to create dynamic policy.", "Unable to establish connection with the PCF." , NULL, dynamic_policy->metadata->create_event->nf_server_interface_metadata, dynamic_policy->metadata->create_event->app_meta));
+
+ if (!pcf_session) {
+ ogs_assert(true == nf_server_send_error(dynamic_policy->metadata->create_event->h.sbi.data, 401, 0, dynamic_policy->metadata->create_event->message, "Failed to create dynamic policy.", "Unable to establish connection with the PCF." , NULL, dynamic_policy->metadata->create_event->nf_server_interface_metadata, dynamic_policy->metadata->create_event->app_meta));
}
ue_net = copy_ue_network_connection_identifier(ue_connection);
@@ -635,10 +636,10 @@ static ue_network_identifier_t *copy_ue_network_connection_identifier(const ue_n
ue_net_connection_copy = ogs_calloc(1, sizeof(ue_network_identifier_t));
if (ue_net_connection_copy) {
if (ue_net_connection->address) ogs_copyaddrinfo(&ue_net_connection_copy->address, ue_net_connection->address);
- if (ue_net_connection->supi) ue_net_connection_copy->supi = ogs_strdup(ue_net_connection->supi);
- if (ue_net_connection->gpsi) ue_net_connection_copy->gpsi = ogs_strdup(ue_net_connection->gpsi);
- if (ue_net_connection->dnn) ue_net_connection_copy->dnn = ogs_strdup(ue_net_connection->dnn);
- if (ue_net_connection->ip_domain) ue_net_connection_copy->ip_domain = ogs_strdup(ue_net_connection->ip_domain);
+ ue_net_connection_copy->supi = msaf_strdup(ue_net_connection->supi);
+ ue_net_connection_copy->gpsi = msaf_strdup(ue_net_connection->gpsi);
+ ue_net_connection_copy->dnn = msaf_strdup(ue_net_connection->dnn);
+ ue_net_connection_copy->ip_domain = msaf_strdup(ue_net_connection->ip_domain);
}
return ue_net_connection_copy;
}
@@ -654,20 +655,20 @@ static void free_ue_network_connection_identifier(ue_network_identifier_t *ue_ne
ogs_free(ue_net_connection);
}
-static void msaf_dynamic_policy_remove(msaf_dynamic_policy_t *msaf_dynamic_policy){
-
- if(!msaf_dynamic_policy) return;
+static void msaf_dynamic_policy_remove(msaf_dynamic_policy_t *msaf_dynamic_policy) {
- if(msaf_dynamic_policy->dynamicPolicyId) {
+ if (!msaf_dynamic_policy) return;
+
+ if (msaf_dynamic_policy->dynamicPolicyId) {
ogs_free(msaf_dynamic_policy->dynamicPolicyId);
msaf_dynamic_policy->dynamicPolicyId = NULL;
}
- if(msaf_dynamic_policy->DynamicPolicy) msaf_api_dynamic_policy_free(msaf_dynamic_policy->DynamicPolicy);
- if(msaf_dynamic_policy->hash) ogs_free(msaf_dynamic_policy->hash);
- if(msaf_dynamic_policy->metadata){
- if(msaf_dynamic_policy->metadata->create_event) msaf_event_free(msaf_dynamic_policy->metadata->create_event);
- if(msaf_dynamic_policy->metadata->delete_event) msaf_event_free(msaf_dynamic_policy->metadata->delete_event);
+ if (msaf_dynamic_policy->DynamicPolicy) msaf_api_dynamic_policy_free(msaf_dynamic_policy->DynamicPolicy);
+ if (msaf_dynamic_policy->hash) ogs_free(msaf_dynamic_policy->hash);
+ if (msaf_dynamic_policy->metadata) {
+ if (msaf_dynamic_policy->metadata->create_event) msaf_event_free(msaf_dynamic_policy->metadata->create_event);
+ if (msaf_dynamic_policy->metadata->delete_event) msaf_event_free(msaf_dynamic_policy->metadata->delete_event);
ogs_free(msaf_dynamic_policy->metadata);
}
@@ -676,24 +677,24 @@ static void msaf_dynamic_policy_remove(msaf_dynamic_policy_t *msaf_dynamic_polic
}
static void ue_connection_details_free(ue_network_identifier_t *ue_connection) {
- if(ue_connection->address) ogs_freeaddrinfo(ue_connection->address);
- if(ue_connection->ip_domain) ogs_free(ue_connection->ip_domain);
+ if (ue_connection->address) ogs_freeaddrinfo(ue_connection->address);
+ if (ue_connection->ip_domain) ogs_free(ue_connection->ip_domain);
ogs_free(ue_connection);
}
-static bool app_session_change_callback(pcf_app_session_t *app_session, void *data){
+static bool app_session_change_callback(pcf_app_session_t *app_session, void *data) {
msaf_dynamic_policy_t *dynamic_policy;
ogs_debug("change callback(app_session=%p, data=%p)", app_session, data);
dynamic_policy = (msaf_dynamic_policy_t *)data;
- if(!app_session){
+ if (!app_session) {
- if(dynamic_policy->metadata->create_event)
+ if (dynamic_policy->metadata->create_event)
{
- ogs_assert(true == nf_server_send_error(dynamic_policy->metadata->create_event->h.sbi.data, 401, 0, dynamic_policy->metadata->create_event->message, "Failed to create dynamic policy.", "Unable to establish connection with the PCF." , NULL, dynamic_policy->metadata->create_event->nf_server_interface_metadata, dynamic_policy->metadata->create_event->app_meta));
+ ogs_assert(true == nf_server_send_error(dynamic_policy->metadata->create_event->h.sbi.data, 401, 0, dynamic_policy->metadata->create_event->message, "Failed to create dynamic policy.", "Unable to establish connection with the PCF." , NULL, dynamic_policy->metadata->create_event->nf_server_interface_metadata, dynamic_policy->metadata->create_event->app_meta));
msaf_dynamic_policy_remove(dynamic_policy);
return true;
}
@@ -702,7 +703,7 @@ static bool app_session_change_callback(pcf_app_session_t *app_session, void *da
return true;
}
- if(app_session && dynamic_policy->metadata->create_event){
+ if (app_session && dynamic_policy->metadata->create_event) {
dynamic_policy->pcf_app_session = app_session;
create_msaf_dynamic_policy_and_send_response(dynamic_policy);
return true;
@@ -751,7 +752,7 @@ free_ogs_hash_dynamic_policy(void *rec, const void *key, int klen, const void *v
return 1;
}
-static bool create_msaf_dynamic_policy_and_send_response(msaf_dynamic_policy_t *dyn_policy){
+static bool create_msaf_dynamic_policy_and_send_response(msaf_dynamic_policy_t *dyn_policy) {
ogs_uuid_t uuid;
char id[OGS_UUID_FORMATTED_LENGTH + 1];
ogs_sbi_response_t *response;
@@ -775,14 +776,14 @@ static bool create_msaf_dynamic_policy_and_send_response(msaf_dynamic_policy_t *
dyn_policy->dynamic_policy_created = time(NULL);
dynamic_policy = msaf_api_dynamic_policy_convertResponseToJSON(dyn_policy->DynamicPolicy);
- if(dynamic_policy) {
+ if (dynamic_policy) {
dynamic_policy_to_hash = cJSON_Print(dynamic_policy);
dyn_policy->hash = calculate_hash(dynamic_policy_to_hash);
} else {
ogs_error("Error converting Dynamic Policy to JSON");
- ogs_free(dyn_policy->DynamicPolicy->dynamic_policy_id);
- ogs_free(dyn_policy->dynamicPolicyId);
- return 0;
+ ogs_free(dyn_policy->DynamicPolicy->dynamic_policy_id);
+ ogs_free(dyn_policy->dynamicPolicyId);
+ return 0;
}
ogs_hash_set(msaf_self()->dynamic_policies, msaf_strdup(id), OGS_HASH_KEY_STRING, dyn_policy);
@@ -798,7 +799,7 @@ static bool create_msaf_dynamic_policy_and_send_response(msaf_dynamic_policy_t *
nf_server_populate_response(response, response_body?strlen(response_body):0, msaf_strdup(response_body), response_code);
ogs_assert(true == ogs_sbi_server_send_response(dyn_policy->metadata->create_event->h.sbi.data, response));
- if(dyn_policy->metadata->create_event)
+ if (dyn_policy->metadata->create_event)
{
msaf_event_free(dyn_policy->metadata->create_event);
dyn_policy->metadata->create_event = NULL;
@@ -821,7 +822,7 @@ static bool app_session_notification_callback(pcf_app_session_t *app_session, co
return true;
}
-static bool bsf_retrieve_pcf_binding_callback(OpenAPI_pcf_binding_t *pcf_binding, void *data){
+static bool bsf_retrieve_pcf_binding_callback(OpenAPI_pcf_binding_t *pcf_binding, void *data) {
int rv;
int valid_time = 50;
ogs_time_t expires;
@@ -835,20 +836,20 @@ static bool bsf_retrieve_pcf_binding_callback(OpenAPI_pcf_binding_t *pcf_binding
ogs_assert(ue_address);
- if(pcf_binding){
+ if (pcf_binding) {
const ogs_sockaddr_t *pcf_address;
expires = ogs_time_now() + ogs_time_from_sec(valid_time);
rv = msaf_pcf_cache_add(msaf_self()->pcf_cache, ue_address, (const OpenAPI_pcf_binding_t *)pcf_binding, expires);
OpenAPI_pcf_binding_free(pcf_binding);
- if (rv != true){
+ if (rv != true) {
ogs_error("Adding PCF Binding to the cache failed");
retrieve_pcf_binding_cb_data_free(retrieve_pcf_binding_cb_data);
return false;
}
pcf_address = msaf_pcf_cache_find(msaf_self()->pcf_cache, retrieve_pcf_binding_cb_data->ue_connection->address);
- if(pcf_address){
+ if (pcf_address) {
create_dynamic_policy_app_session(pcf_address, retrieve_pcf_binding_cb_data->ue_connection, retrieve_pcf_binding_cb_data->media_component, retrieve_pcf_binding_cb_data->dyn_policy);
retrieve_pcf_binding_cb_data_free(retrieve_pcf_binding_cb_data);
return true;
@@ -930,7 +931,7 @@ static char *flow_description_protocol_to_string(int protocol)
static char *flow_description_port(int port)
{
- if (port == 0) return ogs_strdup("");
+ if (port == 0) return msaf_strdup("");
return ogs_msprintf(" %d", port);
}
diff --git a/src/5gmsaf/dynamic-policy.h b/src/5gmsaf/dynamic-policy.h
index 33cba2b..4b9ddd6 100644
--- a/src/5gmsaf/dynamic-policy.h
+++ b/src/5gmsaf/dynamic-policy.h
@@ -1,12 +1,12 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-Copyright: (C) 2022-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Author: Dev Audsin
+ * Copyright: (C) 2022-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 MSAF_DYN_POLICY_H
#define MSAF_DYN_POLICY_H
diff --git a/src/5gmsaf/event.c b/src/5gmsaf/event.c
index e8c5646..8abc82b 100644
--- a/src/5gmsaf/event.c
+++ b/src/5gmsaf/event.c
@@ -1,11 +1,11 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-Copyright: (C) 2022-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
+ * License: 5G-MAG Public License (v1.0)
+ * Author: Dev Audsin
+ * Copyright: (C) 2022-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 "context.h"
@@ -44,7 +44,7 @@ int check_event_addresses(msaf_event_t *e, ogs_sockaddr_t *sockaddr_v4, ogs_sock
(sockaddr_v6 && ogs_sockaddr_is_equal(server->node.addr, sockaddr_v6))
) {
return 1;
- }
+ }
}
return 0;
@@ -66,7 +66,7 @@ msaf_event_t *populate_msaf_event_with_metadata(msaf_event_t *e, const nf_server
if (rv != OGS_OK) {
ogs_error("ogs_sbi_parse_header() failed");
}
-
+
event->nf_server_interface_metadata = nf_server_interface_metadata;
event->app_meta = msaf_app_metadata();
diff --git a/src/5gmsaf/event.h b/src/5gmsaf/event.h
index 3a1972e..78fb361 100644
--- a/src/5gmsaf/event.h
+++ b/src/5gmsaf/event.h
@@ -1,11 +1,11 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-Copyright: (C) 2022-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
+ * License: 5G-MAG Public License (v1.0)
+ * Author: Dev Audsin
+ * Copyright: (C) 2022-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 MSAF_EVENT_H
diff --git a/src/5gmsaf/generator-5gmsaf b/src/5gmsaf/generator-5gmsaf
index 832c80a..09d79c2 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 TS26512_M1_ConsumptionReportingProvisioning TS26512_M1_PolicyTemplatesProvisioning TS26512_M1_MetricsReportingProvisioning M3_ContentHostingProvisioning M3_ServerCertificatesProvisioning TS26512_M5_ServiceAccessInformation TS26512_M5_ConsumptionReporting TS26512_M5_NetworkAssistance TS26512_M5_DynamicPolicies Maf_Management"
+default_apis="TS26512_M1_ProvisioningSessions TS26512_M1_ContentHostingProvisioning TS26512_M1_ServerCertificatesProvisioning TS26512_M1_ContentProtocolsDiscovery TS26512_M1_ConsumptionReportingProvisioning TS26512_M1_PolicyTemplatesProvisioning TS26512_M1_MetricsReportingProvisioning M3_ContentHostingProvisioning M3_ServerCertificatesProvisioning TS26512_M5_ServiceAccessInformation TS26512_M5_ConsumptionReporting TS26512_M5_NetworkAssistance TS26512_M5_DynamicPolicies Maf_Management TS26512_M5_MetricsReporting"
# Parse command line arguments
ARGS=`getopt -n "$scriptname" -o 'a:b:hM:' -l 'api:,branch:,help,model-deps:' -s sh -- "$@"`
@@ -118,7 +118,7 @@ destdir=`realpath -m "$scriptdir/openapi"`
openapi_gen_dir=`realpath "$scriptdir/../../subprojects/open5gs/lib/sbi/support/r17-20230301-openapitools-6.4.0/openapi-generator"`
sed "s@^templateDir:.*@templateDir: \"${openapi_gen_dir}/templates\"@" $openapi_gen_dir/config.yaml > $scriptdir/config.yaml
-cp "${scriptdir}/openapi-templates/"*.mustache "${openapi_gen_dir}/templates/"
+cp "${scriptdir}/../../subprojects/rt-common-shared/open5gs-tools/openapi-generator-templates/c/"*.mustache "${openapi_gen_dir}/templates/"
cat >> $scriptdir/config.yaml << EOF
importMappings:
set: set
@@ -141,7 +141,9 @@ if [ ! -d "$scriptdir/openapi" ]; then
mkdir "$scriptdir/openapi"
fi
-if ! "$scriptdir/../../subprojects/rt-common-shared/5gms/scripts/generate_openapi" -a "${APIS}" -b "${BRANCH}" -c "$scriptdir/config.yaml" -l c -d "$scriptdir/openapi" -g 6.4.0 -y "$scriptdir/fix_openapi_yaml.py" -p "MSAF_API"; then
+rt_common_shared="$scriptdir/../../subprojects/rt-common-shared"
+
+if ! "$rt_common_shared/open5gs-tools/scripts/generate_openapi" -a "${APIS}" -b "${BRANCH}" -o "$scriptdir/openapi-extra-yaml:$scriptdir/5G_APIs-overrides:$rt_common_shared/5gms/5G_APIs-overrides" -c "$scriptdir/config.yaml" -l c -d "$scriptdir/openapi" -g 6.4.0 -y "$scriptdir/fix_openapi_yaml.py" -p "MSAF_API"; then
echo "Error: Failed to generate OpenAPI model" 1>&2
exit 1
fi
diff --git a/src/5gmsaf/hash.c b/src/5gmsaf/hash.c
index 427371b..69fafeb 100644
--- a/src/5gmsaf/hash.c
+++ b/src/5gmsaf/hash.c
@@ -1,12 +1,12 @@
/*
-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
+ */
#include "hash.h"
diff --git a/src/5gmsaf/hash.h b/src/5gmsaf/hash.h
index 60f76df..9435655 100644
--- a/src/5gmsaf/hash.h
+++ b/src/5gmsaf/hash.h
@@ -1,12 +1,12 @@
/*
-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_HASH_H
#define MSAF_HASH_H
diff --git a/src/5gmsaf/headers.c b/src/5gmsaf/headers.c
index abd9163..73b0407 100644
--- a/src/5gmsaf/headers.c
+++ b/src/5gmsaf/headers.c
@@ -1,6 +1,6 @@
/*
* License: 5G-MAG Public License (v1.0)
- * Author: David Waring
+ * Author: David Waring
* Copyright: (C) 2023 British Broadcasting Corporation
*
* For full license terms please see the LICENSE file distributed with this
@@ -122,7 +122,7 @@ static int _hash_do_callback(void *rec, const void *key, int key_len, const void
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);
}
diff --git a/src/5gmsaf/headers.h b/src/5gmsaf/headers.h
index 71da4bf..d5eee9f 100644
--- a/src/5gmsaf/headers.h
+++ b/src/5gmsaf/headers.h
@@ -1,6 +1,6 @@
/*
* License: 5G-MAG Public License (v1.0)
- * Author: David Waring
+ * Author: David Waring
* Copyright: (C) 2023 British Broadcasting Corporation
*
* For full license terms please see the LICENSE file distributed with this
diff --git a/src/5gmsaf/init.c b/src/5gmsaf/init.c
index 79ef927..7e0f807 100644
--- a/src/5gmsaf/init.c
+++ b/src/5gmsaf/init.c
@@ -1,12 +1,13 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-Copyright: (C) 2022-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Authors: Dev Audsin
+ * David Waring
+ * Copyright: (C) 2022-2024 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 "bsf-service-consumer.h"
@@ -128,7 +129,7 @@ static void msaf_main(void *data)
int rv;
ogs_fsm_init(&msaf_sm, msaf_state_initial, msaf_state_final, 0);
-
+
for ( ;; ) {
ogs_pollset_poll(ogs_app()->pollset,
ogs_timer_mgr_next(ogs_app()->timer_mgr));
@@ -155,20 +156,20 @@ static void msaf_main(void *data)
}
}
done:
-
+
ogs_fsm_fini(&msaf_sm, 0);
-
+
}
static int msaf_set_time(void)
{
- if(ogs_env_set("TZ", "GMT") != OGS_OK)
+ 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)
+ if (ogs_env_set("LC_TIME", "C") != OGS_OK)
{
ogs_error("Failed to set LC_TIME to C");
return OGS_ERROR;
diff --git a/src/5gmsaf/init.h b/src/5gmsaf/init.h
index 13ce361..46a4954 100644
--- a/src/5gmsaf/init.h
+++ b/src/5gmsaf/init.h
@@ -1,11 +1,12 @@
/*
-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
-*/
+ * 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_INIT_H
#define MSAF_INIT_H
diff --git a/src/5gmsaf/local.c b/src/5gmsaf/local.c
index eeb6466..27f46a8 100644
--- a/src/5gmsaf/local.c
+++ b/src/5gmsaf/local.c
@@ -1,12 +1,13 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Authors: Dev Audsin
+ * David Waring
+ * Copyright: (C) 2023-2024 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-proto.h"
#include "ogs-sbi.h"
@@ -29,62 +30,62 @@ bool local_process_event(msaf_event_t *e)
switch (e->h.id) {
case MSAF_EVENT_SBI_LOCAL:
{
- if(e->local_id == MSAF_LOCAL_EVENT_POLICY_TEMPLATE_STATE_CHANGE) {
- msaf_policy_template_change_state_event_data_t *msaf_policy_template_change_state_event_data;
- msaf_provisioning_session_t *provisioning_session;
- msaf_provisioning_session_t *provisioning_sess;
- msaf_policy_template_node_t *msaf_policy_template_node;
- msaf_policy_template_node_t *msaf_policy_template;
- const char *policy_template_id;
- const char *provisioning_session_id;
+ if (e->local_id == MSAF_LOCAL_EVENT_POLICY_TEMPLATE_STATE_CHANGE) {
+ msaf_policy_template_change_state_event_data_t *msaf_policy_template_change_state_event_data;
+ msaf_provisioning_session_t *provisioning_session;
+ msaf_provisioning_session_t *provisioning_sess;
+ msaf_policy_template_node_t *msaf_policy_template_node;
+ msaf_policy_template_node_t *msaf_policy_template;
+ const char *policy_template_id;
+ const char *provisioning_session_id;
msaf_policy_template_change_state_event_data = (msaf_policy_template_change_state_event_data_t *)e->data;
- provisioning_session = msaf_policy_template_change_state_event_data->provisioning_session;
+ provisioning_session = msaf_policy_template_change_state_event_data->provisioning_session;
msaf_policy_template_node = msaf_policy_template_change_state_event_data->policy_template_node;
- policy_template_id = msaf_policy_template_node->policy_template->policy_template_id;
-
- provisioning_session_id = provisioning_session->provisioningSessionId;
-
- provisioning_sess = msaf_provisioning_session_find_by_provisioningSessionId(provisioning_session_id);
- if(provisioning_sess) {
- msaf_policy_template = msaf_provisioning_session_find_policy_template_by_id(provisioning_session, policy_template_id);
- if(msaf_policy_template && (msaf_policy_template_node == msaf_policy_template)) {
-
- if(msaf_policy_template_set_state(msaf_policy_template->policy_template, msaf_policy_template_change_state_event_data->new_state, provisioning_sess)) {
- ogs_info("msaf_policy_template->policy_template->state: %d", msaf_policy_template->policy_template->state);
- msaf_policy_template->last_modified = time(NULL);
- if(msaf_policy_template->hash) ogs_free(msaf_policy_template->hash);
+ policy_template_id = msaf_policy_template_node->policy_template->policy_template_id;
+
+ provisioning_session_id = provisioning_session->provisioningSessionId;
+
+ provisioning_sess = msaf_provisioning_session_find_by_provisioningSessionId(provisioning_session_id);
+ if (provisioning_sess) {
+ msaf_policy_template = msaf_provisioning_session_find_policy_template_by_id(provisioning_session, policy_template_id);
+ if (msaf_policy_template && (msaf_policy_template_node == msaf_policy_template)) {
+
+ if (msaf_policy_template_set_state(msaf_policy_template->policy_template, msaf_policy_template_change_state_event_data->new_state, provisioning_sess)) {
+ ogs_info("msaf_policy_template->policy_template->state: %d", msaf_policy_template->policy_template->state);
+ msaf_policy_template->last_modified = time(NULL);
+ if (msaf_policy_template->hash) ogs_free(msaf_policy_template->hash);
msaf_policy_template->hash = calculate_policy_template_hash(msaf_policy_template->policy_template);
- //MVP: going straight to READY state from PENDING
- if(msaf_policy_template->policy_template->state == msaf_api_policy_template_STATE_PENDING) {
- ogs_debug("MVP: set to msaf_api_policy_template_STATE_READY");
- msaf_provisioning_session_send_policy_template_state_change_event(provisioning_sess, msaf_policy_template, msaf_api_policy_template_STATE_READY, NULL, NULL);
- }
- ogs_info("msaf_policy_template->policy_template->state: %d", msaf_policy_template->policy_template->state);
-
- if(msaf_policy_template_change_state_event_data->callback) {
- msaf_policy_template_change_state_event_data->callback(msaf_policy_template_change_state_event_data->provisioning_session, msaf_policy_template_change_state_event_data->policy_template_node, msaf_policy_template_change_state_event_data->new_state, msaf_policy_template_change_state_event_data->callback_user_data);
-
- }
-
- }
-
- } else {
- ogs_error("Policy template not found");
- policy_template_state_change_local_event_data_free(e);
+ //MVP: going straight to READY state from PENDING
+ if (msaf_policy_template->policy_template->state == msaf_api_policy_template_STATE_VAL_PENDING) {
+ ogs_debug("MVP: set to msaf_api_policy_template_STATE_READY");
+ msaf_provisioning_session_send_policy_template_state_change_event(provisioning_sess, msaf_policy_template, msaf_api_policy_template_STATE_VAL_READY, NULL, NULL);
+ }
+ ogs_info("msaf_policy_template->policy_template->state: %d", msaf_policy_template->policy_template->state);
+
+ if (msaf_policy_template_change_state_event_data->callback) {
+ msaf_policy_template_change_state_event_data->callback(msaf_policy_template_change_state_event_data->provisioning_session, msaf_policy_template_change_state_event_data->policy_template_node, msaf_policy_template_change_state_event_data->new_state, msaf_policy_template_change_state_event_data->callback_user_data);
+
+ }
+
+ }
+
+ } else {
+ ogs_error("Policy template not found");
+ policy_template_state_change_local_event_data_free(e);
return false;
-
- }
- }
+ }
+
+ }
ogs_debug("taking event for OGS_EVENT_SBI_LOCAL");
- policy_template_state_change_local_event_data_free(e);
- return true;
+ policy_template_state_change_local_event_data_free(e);
+ return true;
+
+ }
- }
-
//break;
//DEFAULT
//END
@@ -92,16 +93,16 @@ bool local_process_event(msaf_event_t *e)
//ogs_debug("end OGS_EVENT_SBI_LOCAL");
//break;
}
- break;
+ break;
default:
break;
}
- return false;
+ return false;
}
static void policy_template_state_change_local_event_data_free(msaf_event_t *e) {
- if(e->data) ogs_free(e->data);
+ if (e->data) ogs_free(e->data);
}
diff --git a/src/5gmsaf/local.h b/src/5gmsaf/local.h
index 146555e..552f0b0 100644
--- a/src/5gmsaf/local.h
+++ b/src/5gmsaf/local.h
@@ -1,11 +1,11 @@
/*
-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_LOCAL_SM_H
diff --git a/src/5gmsaf/meson.build b/src/5gmsaf/meson.build
index b59a3f3..a56a097 100644
--- a/src/5gmsaf/meson.build
+++ b/src/5gmsaf/meson.build
@@ -34,6 +34,8 @@ libmsaf_dist_sources = files('''
application-server-context.c
certmgr.c
certmgr.h
+ metrics-reporting-configuration.c
+ metrics-reporting-configuration.h
consumption-report-configuration.c
consumption-report-configuration.h
context.c
diff --git a/src/5gmsaf/metrics-reporting-configuration.c b/src/5gmsaf/metrics-reporting-configuration.c
new file mode 100644
index 0000000..4cad218
--- /dev/null
+++ b/src/5gmsaf/metrics-reporting-configuration.c
@@ -0,0 +1,151 @@
+/*
+ * License: 5G-MAG Public License (v1.0)
+ * Author: Vuk Stojkovic
+ * Copyright: (C) 2023-2024 Fraunhofer FOKUS
+ *
+ * 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 "hash.h"
+#include "utilities.h"
+#include "provisioning-session.h"
+#include "metrics-reporting-configuration.h"
+
+
+ogs_hash_t * msaf_metrics_reporting_map(void)
+{
+ ogs_hash_t *metrics_reporting_map = ogs_hash_make();
+ return metrics_reporting_map;
+}
+
+static char *calculate_metrics_reporting_configuration_hash(msaf_api_metrics_reporting_configuration_t *metrics_reporting_configuration)
+{
+ if (!metrics_reporting_configuration) {
+ ogs_error("Metrics object not found.");
+ return NULL;
+ }
+
+ cJSON *metrics_configuration_json = msaf_api_metrics_reporting_configuration_convertResponseToJSON(metrics_reporting_configuration);
+
+ if (!metrics_configuration_json) {
+ ogs_error("Conversion to JSON failed.");
+ return NULL;
+ }
+
+ char *metrics_configuration_to_hash = cJSON_PrintUnformatted(metrics_configuration_json);
+
+ if (!metrics_configuration_to_hash) {
+ cJSON_Delete(metrics_configuration_json);
+ return NULL;
+ }
+
+ char *metrics_configuration_hashed = calculate_hash(metrics_configuration_to_hash);
+
+ cJSON_free(metrics_configuration_to_hash);
+ cJSON_Delete(metrics_configuration_json);
+
+ return metrics_configuration_hashed;
+}
+
+msaf_metrics_reporting_configuration_t* process_and_map_metrics_reporting_configuration(msaf_provisioning_session_t *provisioning_session, msaf_api_metrics_reporting_configuration_t *parsed_config)
+{
+
+ ogs_assert(provisioning_session);
+ ogs_assert(parsed_config);
+
+ ogs_uuid_t uuid;
+ ogs_uuid_get(&uuid);
+ char new_id[OGS_UUID_FORMATTED_LENGTH + 1];
+ ogs_uuid_format(new_id, &uuid);
+
+ if (parsed_config->metrics_reporting_configuration_id != NULL) {
+ ogs_free(parsed_config->metrics_reporting_configuration_id);
+ }
+ parsed_config->metrics_reporting_configuration_id = msaf_strdup(new_id);
+
+ msaf_metrics_reporting_configuration_t *msaf_metrics_config = ogs_calloc(1, sizeof(msaf_metrics_reporting_configuration_t));
+
+ if (!msaf_metrics_config) {
+ ogs_error("Failed to allocate msaf_metrics_reporting_configuration");
+ return NULL;
+ }
+
+ msaf_metrics_config->config = parsed_config;
+ msaf_metrics_config->etag = calculate_metrics_reporting_configuration_hash(msaf_metrics_config->config);
+ msaf_metrics_config->receivedTime = time(NULL);
+
+ if (provisioning_session->metrics_reporting_map == NULL) {
+ provisioning_session->metrics_reporting_map = msaf_metrics_reporting_map();
+ }
+
+ char *hashKey = msaf_strdup(msaf_metrics_config->config->metrics_reporting_configuration_id);
+ ogs_hash_set(provisioning_session->metrics_reporting_map, hashKey, OGS_HASH_KEY_STRING, msaf_metrics_config);
+
+ return msaf_metrics_config;
+}
+
+msaf_metrics_reporting_configuration_t* msaf_metrics_reporting_configuration_retrieve(const msaf_provisioning_session_t *provisioning_session, const char *metrics_configuration_id) {
+ if (!provisioning_session || !metrics_configuration_id) {
+ return NULL;
+ }
+ return (msaf_metrics_reporting_configuration_t*)ogs_hash_get(provisioning_session->metrics_reporting_map, metrics_configuration_id, OGS_HASH_KEY_STRING);
+}
+
+int msaf_delete_metrics_configuration(msaf_provisioning_session_t *provisioning_session, const char *metrics_configuration_id) {
+
+ msaf_metrics_reporting_configuration_t *metrics_config = msaf_metrics_reporting_configuration_retrieve(provisioning_session, metrics_configuration_id);
+
+ if (!metrics_config) return -1;
+
+ msaf_metrics_reporting_configuration_free(metrics_config);
+
+ ogs_hash_set(provisioning_session->metrics_reporting_map, msaf_strdup(metrics_configuration_id), OGS_HASH_KEY_STRING, NULL);
+
+ return 0;
+}
+
+void msaf_metrics_reporting_configuration_free(msaf_metrics_reporting_configuration_t *metrics_config)
+{
+ if (!metrics_config) return;
+
+ if (metrics_config->config) {
+ msaf_api_metrics_reporting_configuration_free(metrics_config->config);
+ metrics_config->config = NULL;
+ }
+
+ if (metrics_config->etag) {
+ ogs_free(metrics_config->etag);
+ }
+
+ ogs_free(metrics_config);
+}
+
+int update_metrics_configuration(msaf_metrics_reporting_configuration_t *existing_metrics_config, msaf_api_metrics_reporting_configuration_t *updated_config) {
+
+ if (!existing_metrics_config || !updated_config) {
+ ogs_error("Null pointers passed");
+ return -1;
+ }
+ if (existing_metrics_config->config->metrics_reporting_configuration_id) {
+ if (updated_config->metrics_reporting_configuration_id) {
+ ogs_free(updated_config->metrics_reporting_configuration_id);
+ }
+ updated_config->metrics_reporting_configuration_id = msaf_strdup(existing_metrics_config->config->metrics_reporting_configuration_id);
+ }
+
+ msaf_api_metrics_reporting_configuration_free(existing_metrics_config->config);
+ existing_metrics_config->config = updated_config;
+
+ if (existing_metrics_config->etag) {
+ ogs_free(existing_metrics_config->etag);
+ }
+ existing_metrics_config->etag = calculate_metrics_reporting_configuration_hash(updated_config);
+ existing_metrics_config->receivedTime = time(NULL);
+
+ return 0;
+}
+
+
diff --git a/src/5gmsaf/metrics-reporting-configuration.h b/src/5gmsaf/metrics-reporting-configuration.h
new file mode 100644
index 0000000..699aba1
--- /dev/null
+++ b/src/5gmsaf/metrics-reporting-configuration.h
@@ -0,0 +1,30 @@
+/*
+ * License: 5G-MAG Public License (v1.0)
+ * Author: Vuk Stojkovic
+ * Copyright: (C) 2023-2024 Fraunhofer Fokus
+ *
+ * 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_METRICS_REPORTING_CONFIGURATION_H
+#define MSAF_METRICS_REPORTING_CONFIGURATION_H
+#include "openapi/model/msaf_api_metrics_reporting_configuration.h"
+
+
+typedef struct msaf_metrics_reporting_configuration_s {
+ msaf_api_metrics_reporting_configuration_t *config;
+ char *etag;
+ time_t receivedTime;
+} msaf_metrics_reporting_configuration_t;
+
+extern ogs_hash_t *msaf_metrics_reporting_map();
+extern msaf_metrics_reporting_configuration_t* process_and_map_metrics_reporting_configuration(msaf_provisioning_session_t *provisioning_session, msaf_api_metrics_reporting_configuration_t *parsed_config);
+extern msaf_metrics_reporting_configuration_t* msaf_metrics_reporting_configuration_retrieve(const msaf_provisioning_session_t *provisioning_session, const char *metrics_configuration_id);
+extern void msaf_metrics_reporting_configuration_free(msaf_metrics_reporting_configuration_t *metrics_config);
+extern cJSON *msaf_metrics_reporting_configuration_convertToJSON(const msaf_metrics_reporting_configuration_t *msaf_metrics_reporting_configuration);
+extern int msaf_delete_metrics_configuration(msaf_provisioning_session_t *provisioning_session, const char *metrics_configuration_id);
+int update_metrics_configuration(msaf_metrics_reporting_configuration_t *existing_metrics_config, msaf_api_metrics_reporting_configuration_t *updated_config);
+
+#endif //MSAF_METRICS_REPORTING_CONFIGURATION_H
diff --git a/src/5gmsaf/msaf-fsm.c b/src/5gmsaf/msaf-fsm.c
index 7870a78..85dddae 100644
--- a/src/5gmsaf/msaf-fsm.c
+++ b/src/5gmsaf/msaf-fsm.c
@@ -1,12 +1,13 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Authors: Dev Audsin
+ * David Waring
+ * Copyright: (C) 2023-2024 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-m1-sm.h"
@@ -17,8 +18,8 @@ program. If this file is missing then the license can be retrieved from
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.servers[MSAF_SVR_MSAF].ipv4 || msaf_self()->config.servers[MSAF_SVR_MSAF].ipv6) {
+ ogs_fsm_init(&msaf_self()->msaf_fsm.msaf_m5_sm, msaf_m5_state_initial, msaf_m5_state_final, 0);
+ if (msaf_self()->config.servers[MSAF_SVR_MSAF].ipv4 || msaf_self()->config.servers[MSAF_SVR_MSAF].ipv6) {
ogs_fsm_init(&msaf_self()->msaf_fsm.msaf_maf_mgmt_sm, msaf_maf_mgmt_state_initial, msaf_maf_mgmt_state_final, 0);
}
}
@@ -26,7 +27,7 @@ void msaf_fsm_init(void) {
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.servers[MSAF_SVR_MSAF].ipv4 || msaf_self()->config.servers[MSAF_SVR_MSAF].ipv6) {
+ if (msaf_self()->config.servers[MSAF_SVR_MSAF].ipv4 || msaf_self()->config.servers[MSAF_SVR_MSAF].ipv6) {
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
index 428051a..62e1c71 100644
--- a/src/5gmsaf/msaf-fsm.h
+++ b/src/5gmsaf/msaf-fsm.h
@@ -1,11 +1,12 @@
/*
-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
-*/
+ * 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_FSM_H
#define MSAF_FSM_H
diff --git a/src/5gmsaf/msaf-m1-sm.c b/src/5gmsaf/msaf-m1-sm.c
index f236879..71ff961 100644
--- a/src/5gmsaf/msaf-m1-sm.c
+++ b/src/5gmsaf/msaf-m1-sm.c
@@ -1,7 +1,9 @@
/*
* License: 5G-MAG Public License (v1.0)
- * Author: Dev Audsin
- * Copyright: (C) 2023 British Broadcasting Corporation
+ * Authors: Dev Audsin
+ * David Waring
+ * Vuk Stojkovic
+ * Copyright: (C) 2023-2024 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
@@ -22,12 +24,14 @@
#include "msaf-version.h"
#include "msaf-sm.h"
#include "utilities.h"
+#include "metrics-reporting-configuration.h"
#include "consumption-report-configuration.h"
#include "provisioning-session.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/TS26512_M1_MetricsReportingProvisioningAPI-info.h"
#include "openapi/api/TS26512_M1_ConsumptionReportingProvisioningAPI-info.h"
#include "openapi/api/M3_ServerCertificatesProvisioningAPI-info.h"
#include "openapi/api/M3_ContentHostingProvisioningAPI-info.h"
@@ -35,6 +39,7 @@
#include "openapi/api/TS26512_M1_PolicyTemplatesProvisioningAPI-info.h"
#include "openapi/api/Maf_ManagementAPI-info.h"
#include "openapi/model/msaf_api_content_hosting_configuration.h"
+#include "openapi/model/msaf_api_metrics_reporting_configuration.h"
#include "openapi/model/msaf_api_consumption_reporting_configuration.h"
#include "msaf-m1-sm.h"
@@ -87,6 +92,12 @@ maf_management_api_metadata = {
MAF_MANAGEMENT_API_VERSION
};
+static const nf_server_interface_metadata_t
+ m1_metricsreportingprovisioning_api_metadata = {
+ M1_METRICSREPORTINGPROVISIONING_API_NAME,
+ M1_METRICSREPORTINGPROVISIONING_API_VERSION
+};
+
static void _policy_template_extra_validation(msaf_api_policy_template_t **policy_template, const char **parse_err);
static void _policy_template_remove_read_only(msaf_api_policy_template_t *policy_template);
@@ -119,6 +130,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
static const nf_server_interface_metadata_t *m1_contenthostingprovisioning_api = &m1_contenthostingprovisioning_api_metadata;
static const nf_server_interface_metadata_t *m1_contentprotocolsdiscovery_api = &m1_contentprotocolsdiscovery_api_metadata;
static const nf_server_interface_metadata_t *m1_servercertificatesprovisioning_api = &m1_servercertificatesprovisioning_api_metadata;
+ static const nf_server_interface_metadata_t *m1_metricsreportingprovisioning_api = &m1_metricsreportingprovisioning_api_metadata;
static const nf_server_interface_metadata_t *m1_consumptionreportingprovisioning_api = &m1_consumptionreportingprovisioning_api_metadata;
static const nf_server_interface_metadata_t *m3_contenthostingprovisioning_api = &m3_contenthostingprovisioning_api_metatdata;
static const nf_server_interface_metadata_t *m1_policytemplatesprovisioning_api = &m1_policytemplatesprovisioning_api_metadata;
@@ -143,7 +155,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
ogs_assert(stream);
message = e->message;
- SWITCH(message->h.service.name)
+ SWITCH(message->h.service.name)
CASE("3gpp-m1")
if (strcmp(message->h.api.version, "v2") != 0) {
char *error;
@@ -174,7 +186,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
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 *err;
const char *type;
type = (const char *)ogs_hash_this_val(hi);
err = ogs_msprintf( "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type);
@@ -190,7 +202,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) {
+ if (msaf_provisioning_session) {
// process the POST body
purge_resource_id_node_t *purge_cache;
msaf_application_server_state_ref_node_t *as_state_ref;
@@ -202,8 +214,8 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
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(assigned_provisioning_sessions_resource->assigned_provisioning_session == msaf_provisioning_session) {
+ ogs_list_for_each(&as_state->assigned_provisioning_sessions,assigned_provisioning_sessions_resource) {
+ 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);
@@ -211,7 +223,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
purge_cache->m1_purge_info = m1_purge_info;
m1_purge_info->refs++;
- if(request->http.content)
+ if (request->http.content)
purge_cache->purge_regex = msaf_strdup(request->http.content);
else
purge_cache->purge_regex = NULL;
@@ -221,7 +233,7 @@ 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 {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("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));
@@ -229,7 +241,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
}
}
} else {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("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));
@@ -248,13 +260,19 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
}
} else {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("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));
ogs_free(err);
}
+ } else {
+ char *err;
+ err = ogs_msprintf("POST for sub-resource [%s] with a sub-resource identifier for Provisioning Session [%s] does not exist.", message->h.resource.component[2], 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));
+ ogs_free(err);
}
} else if (message->h.resource.component[1] && message->h.resource.component[2] &&
@@ -266,6 +284,9 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
CASE("consumption-reporting-configuration")
api = m1_consumptionreportingprovisioning_api;
break;
+ CASE("metrics-reporting-configurations")
+ api = m1_metricsreportingprovisioning_api;
+ break;
CASE("content-hosting-configuration")
api = m1_contenthostingprovisioning_api;
break;
@@ -280,16 +301,21 @@ 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) {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("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, api, app_meta));
+ ogs_assert(true == nf_server_send_error(stream, 404, 3, message,
+ "Provisioning session does not exist.", err, NULL,
+ api?api:m1_provisioningsession_api, app_meta));
ogs_free(err);
} else if (!api) {
- char *err = NULL;
- err = ogs_msprintf("Unknown sub resource [%s] for provisioning session [%s]", message->h.resource.component[2], message->h.resource.component[1]);
+ char *err;
+ err = ogs_msprintf("Unknown sub resource [%s] for provisioning session [%s]",
+ message->h.resource.component[2], 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_provisioningsession_api, app_meta));
+ ogs_assert(true == nf_server_send_error(stream, 404, 3, message,
+ "Provisioning session does not exist.", err, NULL,
+ m1_provisioningsession_api, app_meta));
ogs_free(err);
} else if (api == m1_contenthostingprovisioning_api) {
// process the POST body
@@ -307,7 +333,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
}
if (!content_hosting_config) {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("Unable to parse Content Hosting Configuration as JSON 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));
@@ -317,17 +343,15 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
rv = msaf_distribution_create(content_hosting_config, msaf_provisioning_session, &reason);
content_hosting_config = NULL;
-
+
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->httpMetadata.contentHostingConfiguration.received,
msaf_provisioning_session->httpMetadata.contentHostingConfiguration.hash,
@@ -340,21 +364,21 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
response = NULL;
cJSON_Delete(chc);
} else {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("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));
ogs_free(err);
}
} else {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("Unable to retrieve certificate 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, "Internal Server Error.", err, NULL, m1_contenthostingprovisioning_api, app_meta));
ogs_free(err);
}
} else {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("Creation of the Content Hosting Configuration failed for the Provisioning Session [%s]: %s", message->h.resource.component[1], reason);
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 400, 2, message, "Creation of the Content Hosting Configuration failed.", err, NULL, m1_contenthostingprovisioning_api, app_meta));
@@ -438,7 +462,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
ogs_hash_set(msaf_provisioning_session->certificate_map, msaf_strdup(csr_cert->id), OGS_HASH_KEY_STRING, msaf_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){
+ 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;
@@ -461,7 +485,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
char *location;
ogs_hash_set(msaf_provisioning_session->certificate_map, msaf_strdup(cert), OGS_HASH_KEY_STRING, 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);
@@ -475,9 +499,9 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
char *location;
new_cert = server_cert_new("newcert", canonical_domain_name, NULL);
ogs_hash_set(msaf_provisioning_session->certificate_map, msaf_strdup(new_cert->id), OGS_HASH_KEY_STRING, msaf_strdup(new_cert->id));
-
+
location = ogs_msprintf("%s/%s", request->h.uri, new_cert->id);
- if(new_cert->cache_control_max_age){
+ 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;
@@ -523,14 +547,73 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
msaf_api_consumption_reporting_configuration_free(report_config);
} else {
ogs_sbi_response_t *response;
-
- response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, api, app_meta);
+
+ response = nf_server_new_response(message->h.uri, NULL, 0, NULL, 0, NULL, api, app_meta);
ogs_assert(response);
- nf_server_populate_response(response, 0, NULL, 204);
+ nf_server_populate_response(response, 0, NULL, 201);
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
}
}
- } else if (api == m1_policytemplatesprovisioning_api) {
+ } else if (api == m1_metricsreportingprovisioning_api) {
+
+ cJSON *json;
+ const char *parse_err = NULL;
+
+ ogs_debug("POST metrics-reporting-configuration");
+ json = cJSON_Parse(request->http.content);
+
+ if (!json) {
+ char *err;
+ err = ogs_msprintf("Bad MetricsReportingConfiguration for provisioning session [%s]", message->h.resource.component[1]);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, 400, 2, message, "Bad request.", err, NULL, api,app_meta));
+ ogs_free(err);
+ } else {
+
+ msaf_api_metrics_reporting_configuration_t *metrics_config;
+ metrics_config = msaf_api_metrics_reporting_configuration_parseRequestFromJSON(json, &parse_err);
+
+ cJSON_Delete(json);
+
+ if (!metrics_config) {
+ char *err;
+ err = ogs_msprintf("Bad MetricsReportingConfiguration for provisioning session [%s]: %s", message->h.resource.component[1], parse_err);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, 400, 2, message, "Bad request.", err, NULL, api,app_meta));
+ ogs_free(err);
+ } else {
+ msaf_metrics_reporting_configuration_t *msaf_new_metrics_config;
+ msaf_new_metrics_config = process_and_map_metrics_reporting_configuration(msaf_provisioning_session,metrics_config);
+
+ ogs_debug(" Metrics Reporting Configuration ID: %s", msaf_new_metrics_config ? msaf_new_metrics_config->config->metrics_reporting_configuration_id : "null");
+
+ if (msaf_new_metrics_config) {
+
+ if (msaf_provisioning_session->sai_cache) {
+ msaf_sai_cache_clear(msaf_provisioning_session->sai_cache);
+ ogs_debug("SAI cache cleared for provisioning session [%s]", message->h.resource.component[1]);
+ }
+
+ ogs_sbi_response_t *response;
+
+ char *location = ogs_msprintf("%s/%s", request->h.uri, msaf_new_metrics_config->config->metrics_reporting_configuration_id);
+
+ response = nf_server_new_response(location, NULL, 0, NULL, 0, NULL, api, app_meta);
+ ogs_assert(response);
+ nf_server_populate_response(response, 0, NULL, 201);
+ ogs_assert(true == ogs_sbi_server_send_response(stream, response));
+ ogs_free(location);
+ } else {
+ char *err;
+ err = ogs_msprintf("Failed to create MetricsReportingConfiguration for provisioning session [%s]", message->h.resource.component[1]);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, 500, 2, message, "Internal Server Error.", err,NULL, api, app_meta));
+ ogs_free(err);
+ }
+ }
+ }
+ }
+ else if (api == m1_policytemplatesprovisioning_api) {
cJSON *policy_template = NULL;
msaf_api_policy_template_t *policy_temp = NULL;
char *pol_temp;
@@ -560,16 +643,17 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
location = ogs_msprintf("%s/%s", request->h.uri, msaf_policy_template->policy_template->policy_template_id);
- //response = nf_server_new_response(location, NULL, msaf_policy_template->last_modified, msaf_policy_template->hash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, m1_policytemplatesprovisioning_api, app_meta);
+ /* If returning the updated policy template in a 200 response, this should use:
+ * response = nf_server_new_response(location, NULL, msaf_policy_template->last_modified, msaf_policy_template->hash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, api, app_meta);
+ */
response = nf_server_new_response(location, NULL, 0, NULL, 0, NULL, api, app_meta);
nf_server_populate_response(response, 0, NULL, 201);
ogs_assert(response);
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
-
- ogs_free(location);
+ ogs_free(location);
} else {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("Problem adding the policy template to the provisioning session [%s].", message->h.resource.component[1]);
ogs_error("%s",err);
ogs_assert(true == nf_server_send_error(stream, 404, 2, message, "Problem adding the policy template.", err, NULL, api, app_meta));
@@ -578,33 +662,33 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
ogs_info("policy template id: %s", policy_temp->policy_template_id);
} else {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("Problem parsing Policy template JSON: %s", parse_err);
ogs_error("%s",err);
ogs_assert(true == nf_server_send_error(stream, 400, 2, message, "Problem parsing Policy template JSON.", err, NULL, api, app_meta));
ogs_free(err);
}
- if (policy_template) cJSON_Delete(policy_template);
+ if (policy_template) cJSON_Delete(policy_template);
if (pol_temp) cJSON_free(pol_temp);
}
- } else if (message->h.resource.component[1] && !message->h.resource.component[2]){
+ } 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) {
- char *err = NULL;
+ if (msaf_provisioning_session) {
+ char *err;
err = ogs_msprintf("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));
ogs_free(err);
} else {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("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));
ogs_free(err);
- }
+ }
} else {
cJSON *entry;
@@ -662,7 +746,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
}
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) {
@@ -693,9 +777,9 @@ 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] && !message->h.resource.component[4]) {
- msaf_provisioning_session_t *msaf_provisioning_session;
+ msaf_provisioning_session_t *msaf_provisioning_session;
const nf_server_interface_metadata_t *api = NULL;
SWITCH(message->h.resource.component[2])
@@ -705,116 +789,160 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
CASE("certificates")
api = m1_servercertificatesprovisioning_api;
break;
+ CASE("metrics-reporting-configurations")
+ api = m1_metricsreportingprovisioning_api;
+ break;
DEFAULT
END
- msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message->h.resource.component[1]);
+ msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(
+ message->h.resource.component[1]);
if (!msaf_provisioning_session) {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("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, api, app_meta));
+ ogs_assert(true == nf_server_send_error(stream, 404, 2, message,
+ "Provisioning session does not exists.", err, NULL,
+ api?api:m1_provisioningsession_api, app_meta));
ogs_free(err);
} else if (!api) {
- char *err = NULL;
- err = ogs_msprintf("Unknown sub-resource [%s] for provisioning session [%s].", message->h.resource.component[2], message->h.resource.component[1]);
+ char *err;
+ err = ogs_msprintf("Unknown sub-resource [%s] for provisioning session [%s].",
+ message->h.resource.component[2], message->h.resource.component[1]);
ogs_error("%s", err);
- ogs_assert(true == nf_server_send_error(stream, 404, 2, message, "Unknown provisioning session sub-resource.", err, NULL, m1_provisioningsession_api, app_meta));
+ ogs_assert(true == nf_server_send_error(stream, 404, 2, message,
+ "Unknown provisioning session sub-resource.", err, NULL,
+ m1_provisioningsession_api, app_meta));
ogs_free(err);
} else if (api == m1_policytemplatesprovisioning_api) {
- 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_policy_template_node_t *msaf_policy_template;
- msaf_policy_template = msaf_provisioning_session_find_policy_template_by_id(msaf_provisioning_session, message->h.resource.component[3]);
- if(msaf_policy_template) {
- cJSON *policy_template;
- char *policy_template_body;
-
- policy_template = msaf_policy_template_convertToJSON(msaf_policy_template->policy_template);
- policy_template_body = cJSON_Print(policy_template);
-
- response = nf_server_new_response(NULL, "application/json", msaf_policy_template->last_modified, msaf_policy_template->hash, msaf_self()->config.server_response_cache_control->m1_provisioning_session_response_max_age, NULL, m1_policytemplatesprovisioning_api, app_meta);
- nf_server_populate_response(response, strlen(policy_template_body), policy_template_body, 200);
- ogs_assert(true == ogs_sbi_server_send_response(stream, response));
- response = NULL;
-
- cJSON_Delete(policy_template);
+ msaf_policy_template_node_t *msaf_policy_template;
+ msaf_policy_template = msaf_provisioning_session_find_policy_template_by_id(
+ msaf_provisioning_session, message->h.resource.component[3]);
+ if (msaf_policy_template) {
+ cJSON *policy_template;
+ char *policy_template_body;
+
+ policy_template = msaf_policy_template_convertToJSON(msaf_policy_template->policy_template);
+ policy_template_body = cJSON_Print(policy_template);
+
+ response = nf_server_new_response(NULL, "application/json", msaf_policy_template->last_modified,
+ msaf_policy_template->hash,
+ msaf_self()->config.server_response_cache_control->
+ m1_provisioning_session_response_max_age,
+ NULL, m1_policytemplatesprovisioning_api, app_meta);
+ nf_server_populate_response(response, strlen(policy_template_body), policy_template_body, 200);
+ ogs_assert(true == ogs_sbi_server_send_response(stream, response));
+ response = NULL;
+
+ cJSON_Delete(policy_template);
+ } else {
+ char *err;
+ err = ogs_msprintf("Provisioning session [%s] has no policy template [%s].",
+ message->h.resource.component[1], message->h.resource.component[3]);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, 404, 3, message,
+ "Policy template does not exists.", err, NULL, api,
+ app_meta));
+ ogs_free(err);
+ }
+ } else if (api == m1_servercertificatesprovisioning_api) {
+ 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);
+ if (!provisioning_session_cert) {
+ char *err;
+ err = ogs_msprintf("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));
+ ogs_free(err);
+ break;
+ }
+ cert = server_cert_retrieve(message->h.resource.component[3]);
+ if (!cert) {
+ char *err;
+ err = ogs_msprintf("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));
+ ogs_free(err);
+ break;
+ }
+ 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 {
- char *err = NULL;
- err = ogs_msprintf("Provisioning session [%s] has no policy template [%s].", message->h.resource.component[1], message->h.resource.component[3]);
- ogs_error("%s", err);
- ogs_assert(true == nf_server_send_error(stream, 404, 3, message, "Policy template does not exists.", err, NULL, m1_policytemplatesprovisioning_api, app_meta));
- ogs_free(err);
+ 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), msaf_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;
+ err = ogs_msprintf("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));
+ ogs_free(err);
+ } else if (cert->return_code == 8) {
+ 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;
+ err = ogs_msprintf("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));
+ ogs_free(err);
+ }
+ msaf_certificate_free(cert);
+ }
+ else if (api == m1_metricsreportingprovisioning_api) {
- }
+ ogs_debug("GET metrics-reporting-configuration");
- } else if (api == m1_servercertificatesprovisioning_api) {
- 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);
- if(!provisioning_session_cert) {
- char *err = NULL;
- err = ogs_msprintf("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));
- ogs_free(err);
- break;
- }
- cert = server_cert_retrieve(message->h.resource.component[3]);
- if (!cert) {
- char *err = NULL;
- err = ogs_msprintf("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));
- ogs_free(err);
- break;
- }
+ msaf_metrics_reporting_configuration_t *metricsReportingConfiguration;
+ metricsReportingConfiguration = msaf_metrics_reporting_configuration_retrieve(msaf_provisioning_session, message->h.resource.component[3]);
- 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;
+ if (!metricsReportingConfiguration) {
+ char *err = ogs_msprintf("Metrics Reporting Configuration [%s] not found", message->h.resource.component[3]);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, 404, 3, message, "Metrics Reporting Configuration not found.", err, NULL, m1_metricsreportingprovisioning_api, app_meta));
+ ogs_free(err);
+ }
+ else {
+ cJSON *mrc_json_data = msaf_api_metrics_reporting_configuration_convertResponseToJSON(metricsReportingConfiguration->config);
+ if (mrc_json_data) {
+ char *metrics_response_body = cJSON_Print(mrc_json_data);
+ if(metrics_response_body) {
+ ogs_debug("Retrieved Metrics Reporting Configuration:\n%s", metrics_response_body);
+ ogs_sbi_response_t *response;
+ response = nf_server_new_response(NULL, "application/json",
+ metricsReportingConfiguration->receivedTime,
+ metricsReportingConfiguration->etag,
+ msaf_self()->config.server_response_cache_control->m1_metrics_reporting_response_max_age,
+ NULL, m1_metricsreportingprovisioning_api, app_meta);
+ nf_server_populate_response(response, strlen(metrics_response_body), metrics_response_body, 200);
+ ogs_assert(true == ogs_sbi_server_send_response(stream, response));
+ response= NULL;
+ cJSON_Delete(mrc_json_data);
+ }
+ else {
+ char *err = ogs_msprintf("Failed to generate JSON string for Metrics Reporting Configuration");
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, 500, 3, message, "Internal Server Error", err, NULL, m1_metricsreportingprovisioning_api, app_meta));
+ ogs_free(err);
}
- 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), msaf_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;
- err = ogs_msprintf("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));
- ogs_free(err);
- } else if(cert->return_code == 8){
- 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;
- err = ogs_msprintf("Certificate [%s] management problem.", cert->id);
+ char *err = ogs_msprintf("Failed to convert Metrics Reporting Configuration to JSON");
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));
+ ogs_assert(true == nf_server_send_error(stream, 500, 3, message, "Internal Server Error", err, NULL, m1_metricsreportingprovisioning_api, app_meta));
ogs_free(err);
}
- msaf_certificate_free(cert);
-
- } else {
- char *err = NULL;
- err = ogs_msprintf("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));
- ogs_free(err);
}
}
} else if (message->h.resource.component[1] && message->h.resource.component[2] && !message->h.resource.component[3]) {
@@ -836,16 +964,21 @@ 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) {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("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, api, app_meta));
+ ogs_assert(true == nf_server_send_error(stream, 404, 2, message,
+ "Provisioning session does not exists.", err, NULL,
+ api?api:m1_provisioningsession_api, app_meta));
ogs_free(err);
} else if (!api) {
- char *err = NULL;
- err = ogs_msprintf("Unknown sub-resource [%s] for provisioning session [%s].", message->h.resource.component[2], message->h.resource.component[1]);
+ char *err;
+ err = ogs_msprintf("Unknown sub-resource [%s] for provisioning session [%s].",
+ message->h.resource.component[2], message->h.resource.component[1]);
ogs_error("%s", err);
- ogs_assert(true == nf_server_send_error(stream, 404, 2, message, "Unknown provisioning session sub-resource.", err, NULL, m1_provisioningsession_api, app_meta));
+ ogs_assert(true == nf_server_send_error(stream, 404, 2, message,
+ "Unknown provisioning session sub-resource.", err, NULL,
+ m1_provisioningsession_api, app_meta));
ogs_free(err);
} else if (api == m1_contenthostingprovisioning_api) {
cJSON *chc;
@@ -862,7 +995,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
cJSON_Delete(chc);
} else {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("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));
@@ -884,7 +1017,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
body = msaf_consumption_report_configuration_body(msaf_provisioning_session);
if (!body) {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("Provisioning Session [%s]: Unable to retrieve the Consumption Reporting 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 Consumption Reporting Configuration.", err, NULL, m1_contenthostingprovisioning_api, app_meta));
@@ -919,7 +1052,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
ogs_assert(response);
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
} else {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("Provisioning Session [%s] is not available.", message->h.resource.component[1]);
ogs_error("%s", err);
@@ -941,6 +1074,9 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
CASE("consumption-reporting-configuration")
api = m1_consumptionreportingprovisioning_api;
break;
+ CASE("metrics-reporting-configurations")
+ api = m1_metricsreportingprovisioning_api;
+ break;
CASE("content-hosting-configuration")
api = m1_contenthostingprovisioning_api;
break;
@@ -955,18 +1091,23 @@ 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) {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("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, api, app_meta));
+ ogs_assert(true == nf_server_send_error(stream, 404, 2, message,
+ "Provisioning session does not exists.", err, NULL,
+ api?api:m1_provisioningsession_api, app_meta));
ogs_free(err);
} else if (!api) {
- char *err = NULL;
- err = ogs_msprintf("Unknown sub-resource [%s] for provisioning Session [%s].", message->h.resource.component[2], message->h.resource.component[1]);
+ char *err;
+ err = ogs_msprintf("Unknown sub-resource [%s] for provisioning Session [%s].",
+ message->h.resource.component[2], message->h.resource.component[1]);
ogs_error("%s", err);
- ogs_assert(true == nf_server_send_error(stream, 404, 2, message, "Unknown provisioning session sub-resource.", err, NULL, m1_provisioningsession_api, app_meta));
+ ogs_assert(true == nf_server_send_error(stream, 404, 2, message,
+ "Unknown provisioning session sub-resource.", err, NULL,
+ m1_provisioningsession_api, app_meta));
ogs_free(err);
} else if (api == m1_contenthostingprovisioning_api) {
if (!message->h.resource.component[3]) {
@@ -977,7 +1118,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
cJSON *content_hosting_config = cJSON_Parse(request->http.content);
if (!content_hosting_config) {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("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, 400, 2, message, "Bad ContentHosting Configuration JSON.", err, NULL, m1_contenthostingprovisioning_api, app_meta));
@@ -991,7 +1132,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
cJSON_free(txt);
}
- if(msaf_provisioning_session->contentHostingConfiguration) {
+ if (msaf_provisioning_session->contentHostingConfiguration) {
msaf_api_content_hosting_configuration_free(msaf_provisioning_session->contentHostingConfiguration);
msaf_provisioning_session->contentHostingConfiguration = NULL;
msaf_sai_cache_clear(msaf_provisioning_session->sai_cache);
@@ -999,7 +1140,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
rv = msaf_distribution_create(content_hosting_config, msaf_provisioning_session, &reason);
content_hosting_config = NULL;
- if (rv){
+ if (rv) {
msaf_application_server_state_update(msaf_provisioning_session);
ogs_debug("Content Hosting Configuration updated successfully");
@@ -1012,14 +1153,14 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
ogs_assert(response);
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
} else {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("Provisioning Session [%s]: Update to Content Hosting Configuration failed: %s", message->h.resource.component[1], reason);
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 400, 2, message, "Failed to update the contentHostingConfiguration.", err, NULL, m1_contenthostingprovisioning_api, app_meta));
ogs_free(err);
}
} else {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("Provisioning Session [%s]: "
"Unknown Content Hosting Configuration sub-resource [%s].",
message->h.resource.component[1],
@@ -1031,13 +1172,75 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
);
ogs_free(err);
}
+ } else if (api == m1_metricsreportingprovisioning_api) {
+ if (message->h.resource.component[3] && !message->h.resource.component[4]) {
+
+ cJSON *json;
+ const char *parse_err = NULL;
+ char *metrics_reporting_configuration_id = message->h.resource.component[3];
+
+ ogs_debug("UPDATE metrics-reporting-configuration");
+
+ msaf_metrics_reporting_configuration_t *metrics_configuration = msaf_metrics_reporting_configuration_retrieve(msaf_provisioning_session, metrics_reporting_configuration_id);
+
+ if (!metrics_configuration) {
+ char *err = ogs_msprintf("Metrics Reporting Configuration [%s] not found", metrics_reporting_configuration_id);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, 404, 3, message, "Metrics Reporting Configuration not found.", err, NULL, api, app_meta));
+ ogs_free(err);
+ return;
+ }
+ else{
+ json = cJSON_Parse(request->http.content);
+ if (!json) {
+ char *err = ogs_msprintf("Bad request body for updating Metrics Reporting Configuration [%s]", metrics_reporting_configuration_id);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, 400, 3, message, "Bad request.", err, NULL, api, app_meta));
+ ogs_free(err);
+ }
+ else {
+ msaf_api_metrics_reporting_configuration_t *updated_config = msaf_api_metrics_reporting_configuration_parseRequestFromJSON(json, &parse_err);
+ cJSON_Delete(json);
+
+ if (!updated_config) {
+ char *err = ogs_msprintf("Unable to parse updated Metrics Reporting Configuration: %s", parse_err);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, 400, 3, message, "Bad request.", err, NULL, api, app_meta));
+ ogs_free(err);
+ } else {
+ int result = update_metrics_configuration(metrics_configuration, updated_config);
+ if (result == 0) {
+
+ if (msaf_provisioning_session->sai_cache) {
+ msaf_sai_cache_clear(msaf_provisioning_session->sai_cache);
+ ogs_debug("SAI cache cleared for provisioning session [%s]", message->h.resource.component[1]);
+ }
+
+ ogs_sbi_response_t *response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, api, app_meta);
+ ogs_assert(response);
+ nf_server_populate_response(response, 0, NULL, 200);
+ ogs_assert(true == ogs_sbi_server_send_response(stream, response));
+ } else {
+ char *err = ogs_msprintf("Failed to update Metrics Reporting Configuration [%s]", metrics_reporting_configuration_id);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, 500, 3, message, "Internal Server Error.", err, NULL, api, app_meta));
+ ogs_free(err);
+ }
+ }
+ }
+ }
+ } else {
+ char *err = ogs_msprintf("Unrecognised Metrics Reporting Configurations operation for provisioning session [%s]", message->h.resource.component[1]);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, 400, 2, message, "Bad request.", err, NULL, api, app_meta));
+ ogs_free(err);
+ }
} else if (api == m1_servercertificatesprovisioning_api) {
if (message->h.resource.component[3] && !message->h.resource.component[4]) {
char *cert_id;
char *cert;
int rv;
ogs_sbi_response_t *response;
- msaf_provisioning_session_t *msaf_provisioning_session;
{
ogs_hash_index_t *hi;
@@ -1045,7 +1248,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
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 *err;
const char *type;
type = ogs_hash_this_val(hi);
err = ogs_msprintf( "Unsupported Media Type: received type: %s, should have been application/x-pem-file", type);
@@ -1062,63 +1265,52 @@ 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) {
- 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 = msaf_strdup(request->http.content);
- rv = server_cert_set(cert_id, cert);
- // response = ogs_sbi_response_new();
+ 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 = msaf_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 ) {
+ 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;
- err = ogs_msprintf("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));
- ogs_free(err);
- } else if(rv == 4 || ! provisioning_session_cert) {
- char *err = NULL;
- err = ogs_msprintf("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));
- ogs_free(err);
- } else if(rv == 5) {
- char *err = NULL;
- err = ogs_msprintf("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));
- ogs_free(err);
- } else if(rv == 6) {
- char *err = NULL;
- err = ogs_msprintf("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));
- ogs_free(err);
- } else {
- char *err = NULL;
- err = ogs_msprintf("There was a certificate management problem for the certificate id [%s].", cert_id);
- ogs_error("%s", err);
+ char *err;
+ err = ogs_msprintf("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));
+ ogs_free(err);
+ } else if (rv == 4 || ! provisioning_session_cert) {
+ char *err;
+ err = ogs_msprintf("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));
+ ogs_free(err);
+ } else if (rv == 5) {
+ char *err;
+ err = ogs_msprintf("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));
+ ogs_free(err);
+ } else if (rv == 6) {
+ char *err;
+ err = ogs_msprintf("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));
+ ogs_free(err);
+ } else {
+ char *err;
+ err = ogs_msprintf("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(err);
- }
- ogs_free(cert);
+ 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(err);
}
-
- } else {
- char *err = NULL;
- err = ogs_msprintf("[%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));
- ogs_free(err);
+ ogs_free(cert);
}
} else if (api == m1_consumptionreportingprovisioning_api) {
cJSON *json;
@@ -1127,7 +1319,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
json = cJSON_Parse(request->http.content);
if (!json) {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("Bad request body while updating ConsumptionReportingConfiguration for Provisioining Session [%s].", message->h.resource.component[1]);
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 400, 2, message, "Bad request.", err, NULL, api, app_meta));
@@ -1138,14 +1330,14 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
config = msaf_consumption_report_configuration_parseJSON(json, &parse_err);
if (!config) {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("Bad request body while updating ConsumptionReportingConfiguration for Provisioining Session [%s]: %s", message->h.resource.component[1], parse_err);
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 400, 2, message, "Bad request.", err, NULL, api, app_meta));
ogs_free(err);
} else {
if (!msaf_consumption_report_configuration_update(msaf_provisioning_session, config)) {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("No ConsumptionReportingConfiguration for Provisioining Session [%s].", message->h.resource.component[1]);
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 404, 2, message, "Not found.", err, NULL, api, app_meta));
@@ -1161,88 +1353,77 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
cJSON_Delete(json);
}
} else if (api == m1_policytemplatesprovisioning_api) {
- ogs_sbi_response_t *response;
- msaf_provisioning_session_t *msaf_provisioning_session;
- msaf_api_policy_template_t *policy_template;
+ ogs_sbi_response_t *response;
+ msaf_api_policy_template_t *policy_template;
- if(!check_http_content_type(request->http,"application/json")){
- ogs_assert(true == nf_server_send_error(stream, 415, 3, message, "Unsupported Media Type.", "Expected content type: application/json", NULL, m1_policytemplatesprovisioning_api, app_meta));
+ if (!check_http_content_type(request->http,"application/json")) {
+ ogs_assert(true == nf_server_send_error(stream, 415, 3, message, "Unsupported Media Type.",
+ "Expected content type: application/json", NULL, api,
+ app_meta));
ogs_sbi_message_free(message);
ogs_free(message);
- return;
+ return;
}
- if(!request->http.content) {
- ogs_assert(true == nf_server_send_error(stream, 400, 3, message, "Bad request.", "Request has no content", NULL, m1_policytemplatesprovisioning_api, app_meta));
+ if (!request->http.content) {
+ ogs_assert(true == nf_server_send_error(stream, 400, 3, message, "Bad request.",
+ "Request has no content", NULL, api, app_meta));
ogs_sbi_message_free(message);
ogs_free(message);
return;
-
- }
-
- msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message->h.resource.component[1]);
-
- if(msaf_provisioning_session) {
- msaf_policy_template_node_t *msaf_policy_template;
- msaf_policy_template = msaf_provisioning_session_find_policy_template_by_id(msaf_provisioning_session, message->h.resource.component[3]);
- if(msaf_policy_template) {
- cJSON *policy_template_received;
- const char *parse_err;
-
- policy_template_received = cJSON_Parse(request->http.content);
-
- policy_template = msaf_policy_template_parseFromJSON(policy_template_received, &parse_err);
- cJSON_Delete(policy_template_received);
-
- _policy_template_extra_validation(&policy_template, &parse_err);
-
- if (!policy_template) {
- char *err = ogs_msprintf("Updating policy template: Could not parse request body as JSON: %s", parse_err);
- ogs_error("%s", err);
- ogs_assert(true == nf_server_send_error(stream, 400, 3, message, "Updating policy template failed.",
- err, NULL, m1_policytemplatesprovisioning_api, app_meta));
- ogs_free(err);
- break;
- }
+ }
- /* validation passed, remove read-only fields if present */
- _policy_template_remove_read_only(policy_template);
+ msaf_policy_template_node_t *msaf_policy_template;
+ msaf_policy_template = msaf_provisioning_session_find_policy_template_by_id(msaf_provisioning_session, message->h.resource.component[3]);
+ if (msaf_policy_template) {
+ cJSON *policy_template_received;
+ const char *parse_err;
- /* update policy template */
- if(msaf_provisioning_session_update_policy_template(msaf_provisioning_session, msaf_policy_template, policy_template)) {
-
- response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_policytemplatesprovisioning_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 {
- const char *err = ogs_msprintf("Internal server error while updating policy template [%s]", message->h.resource.component[3]);
- ogs_error("%s", err);
- ogs_assert(true == nf_server_send_error(stream, 400, 3, message, "Updating policy template failed.",
- err, NULL, m1_policytemplatesprovisioning_api, app_meta));
- }
-
+ policy_template_received = cJSON_Parse(request->http.content);
- } else {
-
- char *err = NULL;
- err = ogs_msprintf("Provisioning session [%s] has no policy template [%s].", message->h.resource.component[1], message->h.resource.component[3]);
+ policy_template = msaf_policy_template_parseFromJSON(policy_template_received, &parse_err);
+ cJSON_Delete(policy_template_received);
+
+ _policy_template_extra_validation(&policy_template, &parse_err);
+
+ if (!policy_template) {
+ char *err = ogs_msprintf("Updating policy template: Could not parse request body as JSON: %s", parse_err);
ogs_error("%s", err);
- ogs_assert(true == nf_server_send_error(stream, 404, 3, message, "Policy template does not exists.", err, NULL, m1_policytemplatesprovisioning_api, app_meta));
+ ogs_assert(true == nf_server_send_error(stream, 400, 3, message,
+ "Updating policy template failed.", err, NULL, api,
+ app_meta));
ogs_free(err);
-
- }
+ break;
+ }
- }
+ /* validation passed, remove read-only fields if present */
+ _policy_template_remove_read_only(policy_template);
- }
+ /* update policy template */
+ if (msaf_provisioning_session_update_policy_template(msaf_provisioning_session,
+ msaf_policy_template, policy_template)) {
+ response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, 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 = ogs_msprintf("Internal server error while updating policy template [%s]",
+ message->h.resource.component[3]);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, 400, 3, message,
+ "Updating policy template failed.", err, NULL, api,
+ app_meta));
+ ogs_free(err);
+ }
+ }
+ }
} else {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("[%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));
+ ogs_assert(true == nf_server_send_error(stream, 404, 1, message, "Resource not found.", err, NULL,
+ m1_provisioningsession_api, app_meta));
ogs_free(err);
}
break;
@@ -1259,6 +1440,9 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
CASE("consumption-reporting-configuration")
api = m1_consumptionreportingprovisioning_api;
break;
+ CASE("metrics-reporting-configurations")
+ api = m1_metricsreportingprovisioning_api;
+ break;
CASE("content-hosting-configuration")
api = m1_contenthostingprovisioning_api;
break;
@@ -1273,25 +1457,30 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message->h.resource.component[1]);
if (!provisioning_session) {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("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, api, app_meta));
+ ogs_assert(true == nf_server_send_error(stream, 404, 2, message,
+ "Provisioning session does not exists.", err, NULL,
+ api?api:m1_provisioningsession_api, app_meta));
ogs_free(err);
} else if (!api) {
- char *err = NULL;
- err = ogs_msprintf("Unknown sub-resource [%s] for provisioning Session [%s].", message->h.resource.component[2], message->h.resource.component[1]);
+ char *err;
+ err = ogs_msprintf("Unknown sub-resource [%s] for provisioning Session [%s].",
+ message->h.resource.component[2], message->h.resource.component[1]);
ogs_error("%s", err);
- ogs_assert(true == nf_server_send_error(stream, 404, 2, message, "Unknown provisioning session sub-resource.", err, NULL, m1_provisioningsession_api, app_meta));
+ ogs_assert(true == nf_server_send_error(stream, 404, 2, message,
+ "Unknown provisioning session sub-resource.", err, NULL,
+ m1_provisioningsession_api, app_meta));
ogs_free(err);
} else if (api == m1_contenthostingprovisioning_api) {
/* Delete ContentHostingConfiguration operations */
if (!message->h.resource.component[3]) {
/* Delete the ContentHostingConfiguration */
ogs_sbi_response_t *response;
- if(provisioning_session && provisioning_session->contentHostingConfiguration) {
+ if (provisioning_session->contentHostingConfiguration) {
msaf_delete_content_hosting_configuration(message->h.resource.component[1]);
msaf_api_content_hosting_configuration_free(provisioning_session->contentHostingConfiguration);
provisioning_session->contentHostingConfiguration = NULL;
@@ -1300,7 +1489,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
nf_server_populate_response(response, 0, NULL, 204);
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
} else {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("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, api, app_meta));
@@ -1308,7 +1497,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
}
} else {
/* Delete the ContentHostingConfiguration with extra field - undefined operation */
- char *err = NULL;
+ char *err;
err = ogs_msprintf("Provisioning Session [%s]: Unknown ContentHostingConfiguration operation.", message->h.resource.component[1]);
ogs_error("%s", err);
@@ -1319,7 +1508,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
if (message->h.resource.component[3]) {
if (message->h.resource.component[4]) {
/* Delete certificate with extra field - undefined operation */
- char *err = NULL;
+ char *err;
err = ogs_msprintf("Provisioning session [%s]: Certificate [%s]: Unknown delete operation.",
message->h.resource.component[1], message->h.resource.component[3]);
ogs_error("%s", err);
@@ -1330,20 +1519,20 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
ogs_sbi_response_t *response;
int rv;
rv = server_cert_delete(message->h.resource.component[3]);
- if ((rv == 0) || (rv == 8)){
+ 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;
+ char *err;
err = ogs_msprintf("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));
ogs_free(err);
} else {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("Certificate management problem for certificate [%s].", 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, api, app_meta));
@@ -1352,37 +1541,87 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
}
} else {
/* Delete certificate without certificate id - undefined operation */
- char *err = NULL;
+ char *err;
err = ogs_msprintf("Provisioning session [%s]: Unknown Certificate Management operation.", message->h.resource.component[1]);
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 400, 2, message, "Bad request", err, NULL, api, app_meta));
ogs_free(err);
}
} else if (api == m1_policytemplatesprovisioning_api) {
- if (message->h.resource.component[3]) {
- if (!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]);
- if (provisioning_session) {
- if (msaf_provisioning_session_delete_policy_template_by_id(provisioning_session, message->h.resource.component[3])) {
- response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_policytemplatesprovisioning_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;
- err = ogs_msprintf("Provisioning session [%s]: Policy template [%s] does not exist.",
- message->h.resource.component[1], message->h.resource.component[3]);
+ if (message->h.resource.component[3]) {
+ if (!message->h.resource.component[4]) {
+ ogs_sbi_response_t *response;
+ if (msaf_provisioning_session_delete_policy_template_by_id(provisioning_session,
+ message->h.resource.component[3])
+ ) {
+ response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m1_policytemplatesprovisioning_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;
+ err = ogs_msprintf("Provisioning session [%s]: Policy template [%s] does not exist.",
+ message->h.resource.component[1], message->h.resource.component[3]);
ogs_error("%s", err);
- ogs_assert(true == nf_server_send_error(stream, 404, 3, message, "Policy template does not exist.", err, NULL, m1_policytemplatesprovisioning_api, app_meta));
+ ogs_assert(true == nf_server_send_error(stream, 404, 3, message,
+ "Policy template does not exist.", err, NULL,
+ api, app_meta));
ogs_free(err);
+ }
+ } else {
+ char *err;
+ err = ogs_msprintf("Provisioning session [%s]: Policy template [%s]: Request for deletion "
+ "of sub-resource [%s] not recognised.",
+ message->h.resource.component[1], message->h.resource.component[3],
+ message->h.resource.component[4]);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, 404, 4, message,
+ "Policy template does not exist.", err, NULL,
+ api, app_meta));
+ ogs_free(err);
+ }
+ } else {
+ char *err;
+ err = ogs_msprintf("Provisioning session [%s]: Cannot perform delete on Policy templates "
+ "without a template id.", message->h.resource.component[1]);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, 404, 2, message,
+ "Policy template does not exist.", err, NULL,
+ api, app_meta));
+ ogs_free(err);
+ }
+ } else if(api == m1_metricsreportingprovisioning_api) {
+ if (message->h.resource.component[3] && !message->h.resource.component[4]) {
+ if (msaf_delete_metrics_configuration(provisioning_session, message->h.resource.component[3]) == 0) {
- }
- }
- }
- }
- } else if (api == m1_consumptionreportingprovisioning_api) {
+ if (provisioning_session->sai_cache) {
+ msaf_sai_cache_clear(provisioning_session->sai_cache);
+ ogs_debug("SAI cache cleared for provisioning session [%s]", message->h.resource.component[1]);
+ }
+
+ ogs_sbi_response_t *response;
+ response = nf_server_new_response(NULL, "application/json", 0, NULL, 0, NULL, m1_metricsreportingprovisioning_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;
+ err = ogs_msprintf("Provisioning session [%s]: Metrics Reporting Configuration [%s] does not exist.", message->h.resource.component[1], message->h.resource.component[3]);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, 404, 3, message, "Metrics Reporting Configuration does not exist.", err, NULL, m1_metricsreportingprovisioning_api, app_meta));
+ ogs_free(err);
+ }
+ } else {
+ char *err;
+ err = ogs_msprintf("Provisioning session [%s]: Policy template operation not recognised.",
+ message->h.resource.component[1]);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, 404, 2, message,
+ "Metrics Reporting Configuration operation does not exist.",
+ err, NULL, api, app_meta));
+ ogs_free(err);
+ }
+ } else if (api == m1_consumptionreportingprovisioning_api) {
if (!message->h.resource.component[3]) {
/* Delete consumption reporting configuration */
if (msaf_consumption_report_configuration_deregister(provisioning_session)) {
@@ -1394,7 +1633,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
} else {
/* Failed to delete consumption reporting configuration - no configuration to delete */
- char *err = NULL;
+ char *err;
err = ogs_msprintf("Provisioning session [%s]: Content Reporting Configuration not found.", message->h.resource.component[1]);
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 404, 2, message, "Not Found", err, NULL, api, app_meta));
@@ -1402,7 +1641,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
}
} else {
/* Delete ConsumptionReportingConfiguration sub-resource - undefined operation */
- char *err = NULL;
+ char *err;
err = ogs_msprintf("Provisioning session [%s]: Unknown Consumption Reporting Configuration operation.", message->h.resource.component[1]);
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 400, 2, message, "Bad request", err, NULL, api, app_meta));
@@ -1416,7 +1655,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message->h.resource.component[1]);
if (!provisioning_session || provisioning_session->marked_for_deletion) {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("Provisioning Session [%s] is not available.", message->h.resource.component[1]);
ogs_error("%s", err);
@@ -1438,7 +1677,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
msaf_provisioning_session_hash_remove(message->h.resource.component[1]);
}
} else {
- char *err = NULL;
+ char *err;
err = ogs_msprintf("[%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));
@@ -1448,9 +1687,8 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
break;
CASE(OGS_SBI_HTTP_METHOD_OPTIONS)
- if (!strcmp(message->h.resource.component[0],"provisioning-sessions")){
+ 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;
@@ -1458,19 +1696,21 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
if (provisioning_session) {
if (message->h.resource.component[2]) {
- if (!strcmp(message->h.resource.component[2],"policy-templates")) {
+ if (!strcmp(message->h.resource.component[2],"policy-templates")) {
if (message->h.resource.component[3]) {
msaf_policy_template_node_t *msaf_policy_template;
msaf_policy_template = msaf_provisioning_session_find_policy_template_by_id(provisioning_session, message->h.resource.component[3]);
- if(msaf_policy_template) {
- 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);
+ if (msaf_policy_template) {
+ static const char methods[] = 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_policytemplatesprovisioning_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;
+ ogs_assert(true == ogs_sbi_server_send_response(stream, response));
+ } else {
+ char *err;
err = ogs_msprintf("Policy template [%s] does not exists", message->h.resource.component[3]);
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 500, 3, message, "Problem obtaining the specified policy template.", err, NULL, m1_policytemplatesprovisioning_api, app_meta));
@@ -1478,27 +1718,31 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
break;
}
- } else {
- methods = ogs_msprintf("%s, %s",OGS_SBI_HTTP_METHOD_POST, OGS_SBI_HTTP_METHOD_OPTIONS);
+ } else {
+ static const char methods[] = OGS_SBI_HTTP_METHOD_POST ", "
+ OGS_SBI_HTTP_METHOD_OPTIONS;
response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_policytemplatesprovisioning_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],"certificates")) {
+ } else 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);
+ if (cert) {
+ static const char methods[] = 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;
+ char *err;
err = ogs_msprintf("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));
@@ -1506,63 +1750,87 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
break;
}
} else {
- methods = ogs_msprintf("%s",OGS_SBI_HTTP_METHOD_POST);
+ static const char methods[] = 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], "metrics-reporting-configurations")) {
+ if (message->h.resource.component[3]) {
+ msaf_metrics_reporting_configuration_t *metrics_configuration = msaf_metrics_reporting_configuration_retrieve(provisioning_session, message->h.resource.component[3]);
+
+ if (!metrics_configuration) {
+ char *err = ogs_msprintf("Metrics Reporting Configuration [%s] does not exist", message->h.resource.component[3]);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, 404, 3, message, "Metrics Reporting Configuration does not exist.", err, NULL, m1_metricsreportingprovisioning_api, app_meta));
+ ogs_free(err);
+ } else {
+ static const char methods[] = OGS_SBI_HTTP_METHOD_GET ", "
+ OGS_SBI_HTTP_METHOD_PUT ", "
+ OGS_SBI_HTTP_METHOD_DELETE ", "
+ OGS_SBI_HTTP_METHOD_OPTIONS;
+ ogs_sbi_response_t *response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_metricsreportingprovisioning_api, app_meta);
+ ogs_assert(response);
+ nf_server_populate_response(response, 0, NULL, 204);
+ ogs_assert(true == ogs_sbi_server_send_response(stream, response));
+ }
+ } else {
+ static const char methods[] = OGS_SBI_HTTP_METHOD_POST ", "
+ OGS_SBI_HTTP_METHOD_OPTIONS;
+ ogs_sbi_response_t *response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_metricsreportingprovisioning_api, app_meta);
+ ogs_assert(response);
+ nf_server_populate_response(response, 0, NULL, 204);
+ 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);
+ static const char methods[] = 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 if (!strcmp(message->h.resource.component[2],"consumption-reporting-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);
+ static const char methods[] = 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_consumptionreportingprovisioning_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],"protocols")) {
- methods = ogs_msprintf("%s, %s", OGS_SBI_HTTP_METHOD_GET, OGS_SBI_HTTP_METHOD_OPTIONS);
+ static const char methods[] = OGS_SBI_HTTP_METHOD_GET ", " OGS_SBI_HTTP_METHOD_OPTIONS;
response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, methods, m1_contentprotocolsdiscovery_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;
+ char *err;
err = ogs_msprintf("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));
ogs_free(err);
}
} else {
- methods = ogs_msprintf("%s, %s, %s", OGS_SBI_HTTP_METHOD_GET, OGS_SBI_HTTP_METHOD_DELETE, OGS_SBI_HTTP_METHOD_OPTIONS);
+ static const char methods[] = 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;
+ char *err;
int number_of_components = 0;
const nf_server_interface_metadata_t *interface = NULL;
- if (message->h.resource.component[2]){
+ if (message->h.resource.component[2]) {
if (!strcmp(message->h.resource.component[2],"certificates")) {
number_of_components = 2;
if (message->h.resource.component[3]) {
@@ -1574,14 +1842,13 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
interface = m1_contenthostingprovisioning_api;
}
- } else if (message->h.resource.component[0]){
- if (!strcmp(message->h.resource.component[0],"provisioning-sessions")){
+ } 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;
-
}
}
err = ogs_msprintf("Method [%s]: [%s] - Provisioning Session [%s] does not exist.", message->h.method, message->h.resource.component[2], message->h.resource.component[1]);
@@ -1591,16 +1858,14 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
}
} else {
- methods = ogs_msprintf("%s, %s",OGS_SBI_HTTP_METHOD_POST, OGS_SBI_HTTP_METHOD_OPTIONS);
+ static const char methods[] = 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;
+ char *err;
err = ogs_msprintf("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));
@@ -1615,23 +1880,23 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
break;
DEFAULT
- char *err = NULL;
+ char *err;
err = ogs_msprintf("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));
ogs_free(err);
END
break;
-
+
CASE("5gmag-rt-management")
if (strcmp(message->h.api.version, "v1") != 0) {
char *error;
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_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_free(error);
break;
- }
+ }
if (!message->h.resource.component[0]) {
const char *error = "Resource required for Management interface";
ogs_error("%s", error);
@@ -1643,29 +1908,29 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
CASE("provisioning-sessions")
SWITCH(message->h.method)
- CASE(OGS_SBI_HTTP_METHOD_GET)
+ CASE(OGS_SBI_HTTP_METHOD_GET)
char *provisioning_sessions = NULL;
ogs_sbi_response_t *response;
provisioning_sessions = enumerate_provisioning_sessions();
- if(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), provisioning_sessions, 200);
ogs_assert(response);
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
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_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_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 = NULL;
+ char *err;
err = ogs_msprintf("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));
@@ -1729,7 +1994,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
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 *err;
const char *type;
type = ogs_hash_this_val(hi);
err = ogs_msprintf( "Unsupported Media Type: received type: %s, should have been application/x-www-form-urlencoded", type);
@@ -1755,21 +2020,21 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
}
- ogs_list_for_each_safe(&as_state->purge_content_hosting_cache, next, content_hosting_cache){
+ 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))
+ 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)) {
+ } 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){
+ 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;
@@ -1784,9 +2049,9 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
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->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);
+ 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");
@@ -1795,11 +2060,11 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
}
- if((response->status == 400) || (response->status == 404) || (response->status == 413) || (response->status == 414) || (response->status == 415) || (response->status == 422) || (response->status == 500) || (response->status == 503)) {
+ if ((response->status == 400) || (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){
+ if (response->http.content) {
purge_cache_err = cJSON_Parse(response->http.content);
char *txt = cJSON_Print(purge_cache_err);
ogs_debug("Parsed JSON: %s", txt);
@@ -1837,25 +2102,25 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
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_free(error);
- ogs_list_for_each_safe(&as_state->purge_content_hosting_cache, next, content_hosting_cache){
+ 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)) {
+ 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->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);
+ 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)) {
+ } 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->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);
+ if (content_hosting_cache->purge_regex) ogs_free(content_hosting_cache->purge_regex);
ogs_free(content_hosting_cache);
}
@@ -1881,10 +2146,10 @@ void msaf_m1_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);
@@ -1893,36 +2158,36 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
}
}
- if(response->status == 405){
+ 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]))
+ 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) {
+ if (content_hosting_configuration) {
ogs_debug("Removing %s from upload_content_hosting_configurations", content_hosting_configuration->state);
ogs_free(content_hosting_configuration->state);
@@ -1931,44 +2196,44 @@ void msaf_m1_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 = NULL, *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){
+ 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");
@@ -1995,22 +2260,22 @@ void msaf_m1_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);
@@ -2028,7 +2293,7 @@ void msaf_m1_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]);
@@ -2071,7 +2336,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
response->http.content);
}
}
- if (response->status == 500){
+ if (response->status == 500) {
ogs_error("Received Internal Server error\n");
}
if (response->status == 503) {
@@ -2080,7 +2345,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
next_action_for_application_server(as_state);
break;
DEFAULT
- char *err = NULL;
+ char *err;
err = ogs_msprintf( "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));
@@ -2102,18 +2367,18 @@ void msaf_m1_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]);
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]))
+ ogs_list_for_each(&as_state->upload_certificates,certificate) {
+ if (!strcmp(certificate->state, message->h.resource.component[1]))
break;
}
- if(certificate) {
+ if (certificate) {
ogs_debug("Removing certificate [%s] from upload_certificates", certificate->state);
@@ -2125,28 +2390,28 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
// ogs_free(upload_cert_id);
}
}
- if(response->status == 405){
+ 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]);
@@ -2155,13 +2420,13 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
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){
+ 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);
@@ -2171,43 +2436,43 @@ void msaf_m1_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 = NULL, *next = NULL;
resource_id_node_t *delete_certificate = NULL, *node = NULL;
- if(as_state->current_certificates) {
- ogs_list_for_each_safe(as_state->current_certificates, next, certificate){
+ 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");
@@ -2220,9 +2485,9 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
}
- ogs_list_for_each_safe(&as_state->delete_certificates, node, delete_certificate){
+ 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);
@@ -2234,22 +2499,22 @@ void msaf_m1_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);
@@ -2267,7 +2532,7 @@ void msaf_m1_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);
@@ -2312,7 +2577,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
response->http.content);
}
}
- if (response->status == 500){
+ if (response->status == 500) {
ogs_error("Received Internal Server error");
}
if (response->status == 503) {
@@ -2321,7 +2586,7 @@ void msaf_m1_state_functional(ogs_fsm_t *s, msaf_event_t *e)
next_action_for_application_server(as_state);
break;
DEFAULT
- char *err = NULL;
+ char *err;
err = ogs_msprintf( "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));
diff --git a/src/5gmsaf/msaf-m1-sm.h b/src/5gmsaf/msaf-m1-sm.h
index 1bace9a..a3ee976 100644
--- a/src/5gmsaf/msaf-m1-sm.h
+++ b/src/5gmsaf/msaf-m1-sm.h
@@ -1,11 +1,11 @@
/*
-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
+ * 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 MSAF_M1_SM_H
diff --git a/src/5gmsaf/msaf-m5-sm.c b/src/5gmsaf/msaf-m5-sm.c
index 1a8ae05..7d64840 100644
--- a/src/5gmsaf/msaf-m5-sm.c
+++ b/src/5gmsaf/msaf-m5-sm.c
@@ -1,7 +1,9 @@
/*
* License: 5G-MAG Public License (v1.0)
- * Author: Dev Audsin
- * Copyright: (C) 2023 British Broadcasting Corporation
+ * Authors: Dev Audsin
+ * David Waring
+ * Vuk Stojkovic
+ * Copyright: (C) 2023-2024 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
@@ -25,6 +27,7 @@
#include "hash.h"
#include "timer.h"
#include "openapi/api/TS26512_M5_ServiceAccessInformationAPI-info.h"
+#include "openapi/api/TS26512_M5_MetricsReportingAPI-info.h"
#include "openapi/api/TS26512_M5_ConsumptionReportingAPI-info.h"
#include "openapi/api/TS26512_M5_NetworkAssistanceAPI-info.h"
#include "openapi/model/msaf_api_consumption_report.h"
@@ -45,6 +48,12 @@ m5_consumptionreporting_api_metadata = {
M5_CONSUMPTIONREPORTING_API_VERSION
};
+static const nf_server_interface_metadata_t
+m5_metricsreporting_api_metadata = {
+ M5_METRICSREPORTING_API_NAME,
+ M5_METRICSREPORTING_API_VERSION
+};
+
static const nf_server_interface_metadata_t
m5_networkassistance_api_metadata = {
M5_NETWORKASSISTANCE_API_NAME,
@@ -58,7 +67,7 @@ m5_dynamicpolicy_api_metadata = {
};
-static bool
+static bool
is_dynamic_policy_create_request_valid(ogs_sbi_request_t *request, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message,
const nf_server_interface_metadata_t *m5_dynamicpolicy_api,
const nf_server_app_metadata_t *app_meta);
@@ -90,6 +99,7 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e)
msaf_sm_debug(e);
static const nf_server_interface_metadata_t *m5_serviceaccessinformation_api = &m5_serviceaccessinformation_api_metadata;
+ static const nf_server_interface_metadata_t *m5_metricsreporting_api = &m5_metricsreporting_api_metadata;
static const nf_server_interface_metadata_t *m5_consumptionreporting_api = &m5_consumptionreporting_api_metadata;
static const nf_server_interface_metadata_t *m5_networkassistance_api = &m5_networkassistance_api_metadata;
static const nf_server_interface_metadata_t *m5_dynamicpolicy_api = &m5_dynamicpolicy_api_metadata;
@@ -105,24 +115,24 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e)
case OGS_FSM_EXIT_SIG:
break;
-
- case MSAF_EVENT_DELIVERY_BOOST_TIMER:
+
+ case MSAF_EVENT_DELIVERY_BOOST_TIMER:
ogs_assert(e);
switch(e->h.timer_id) {
case MSAF_TIMER_DELIVERY_BOOST:
- {
- msaf_network_assistance_session_t *na_sess = NULL;
- na_sess = e->network_assistance_session;
- ogs_assert(na_sess);
- ogs_info("MSAF_EVENT_DELIVERY_BOOST_TIMER: MSAF_TIMER_DELIVERY_BOOST");
-
- msaf_nw_assistance_session_update_pcf_on_timeout(na_sess);
- }
- break;
+ {
+ msaf_network_assistance_session_t *na_sess = NULL;
+ na_sess = e->network_assistance_session;
+ ogs_assert(na_sess);
+ ogs_info("MSAF_EVENT_DELIVERY_BOOST_TIMER: MSAF_TIMER_DELIVERY_BOOST");
+
+ msaf_nw_assistance_session_update_pcf_on_timeout(na_sess);
+ }
+ break;
default:
ogs_error("Invalid timer for event %s", msaf_event_get_name(e));
break;
-
+
}
break;
@@ -133,7 +143,7 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e)
ogs_assert(stream);
message = e->message;
- SWITCH(message->h.service.name)
+ SWITCH(message->h.service.name)
CASE("3gpp-m5")
if (strcmp(message->h.api.version, "v2") != 0) {
char *error;
@@ -144,22 +154,22 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e)
break;
}
SWITCH(message->h.resource.component[0])
- CASE("dynamic-policies")
+ CASE("dynamic-policies")
SWITCH(message->h.method)
- CASE(OGS_SBI_HTTP_METHOD_DELETE)
- if(message->h.resource.component[1] && !message->h.resource.component[2])
+ CASE(OGS_SBI_HTTP_METHOD_DELETE)
+ if (message->h.resource.component[1] && !message->h.resource.component[2])
{
msaf_dynamic_policy_t *msaf_dynamic_policy = NULL;
- msaf_dynamic_policy = msaf_dynamic_policy_find_by_dynamicPolicyId(message->h.resource.component[1]);
- if(!msaf_dynamic_policy) {
- char *err = NULL;
+ msaf_dynamic_policy = msaf_dynamic_policy_find_by_dynamicPolicyId(message->h.resource.component[1]);
+ if (!msaf_dynamic_policy) {
+ char *err = NULL;
err = ogs_msprintf("The AF has no dynamic policy with id [%s].", message->h.resource.component[1]);
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 404, 1, message, "Deleting dynamic policy failed.",
err, NULL, m5_dynamicpolicy_api, app_meta));
ogs_free(err);
- break;
+ break;
}
dynamic_policy_event = (msaf_event_t*)populate_msaf_event_with_metadata(e, m5_dynamicpolicy_api, app_meta);
@@ -170,39 +180,39 @@ void msaf_m5_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])
- {
- ogs_sbi_response_t *response;
- cJSON *dynamic_policy = NULL;
- int response_code = 200;
- msaf_dynamic_policy_t *msaf_dynamic_policy;
+ CASE(OGS_SBI_HTTP_METHOD_GET)
+ if (message->h.resource.component[1] && !message->h.resource.component[2])
+ {
+ ogs_sbi_response_t *response;
+ cJSON *dynamic_policy = NULL;
+ int response_code = 200;
+ msaf_dynamic_policy_t *msaf_dynamic_policy;
char *body;
char *hash;
dynamic_policy = msaf_dynamic_policy_get_json(message->h.resource.component[1]);
-
- if(!dynamic_policy) {
- const char *err = "Dynamic policy not found";
+
+ if (!dynamic_policy) {
+ const char *err = "Dynamic policy not found";
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 404, 1, message, "Retrieving dynamic policy failed.",
err, NULL, m5_dynamicpolicy_api, app_meta));
- ogs_sbi_message_free(message);
+ ogs_sbi_message_free(message);
ogs_free(message);
return;
- }
+ }
- body = cJSON_Print(dynamic_policy);
+ body = cJSON_Print(dynamic_policy);
hash= calculate_hash(body);
- msaf_dynamic_policy = msaf_dynamic_policy_find_by_dynamicPolicyId((const char *)message->h.resource.component[1]);
+ msaf_dynamic_policy = msaf_dynamic_policy_find_by_dynamicPolicyId((const char *)message->h.resource.component[1]);
response = nf_server_new_response(request->h.uri, "application/json",
msaf_dynamic_policy->dynamic_policy_created, hash,
msaf_self()->config.server_response_cache_control->m5_service_access_information_response_max_age,
NULL, m5_dynamicpolicy_api, app_meta);
ogs_assert(response);
- nf_server_populate_response(response, strlen(body), ogs_strdup(body), response_code);
+ nf_server_populate_response(response, strlen(body), msaf_strdup(body), response_code);
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
ogs_free(hash);
@@ -210,11 +220,11 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e)
cJSON_free(body);
-
- }
- break;
- CASE(OGS_SBI_HTTP_METHOD_POST)
- {
+
+ }
+ break;
+ CASE(OGS_SBI_HTTP_METHOD_POST)
+ {
cJSON *dynamic_policy;
if (!is_dynamic_policy_create_request_valid (request, stream, message, m5_dynamicpolicy_api, app_meta)) return;
@@ -225,7 +235,7 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e)
dynamic_policy_event = (msaf_event_t*)populate_msaf_event_with_metadata(e, m5_dynamicpolicy_api, app_meta);
- if(!msaf_dynamic_policy_create(dynamic_policy, dynamic_policy_event)) {
+ if (!msaf_dynamic_policy_create(dynamic_policy, dynamic_policy_event)) {
const char *err = "Problem in obtaining the information required to create the Dynamic Policy";
ogs_error("%s", err);
@@ -236,79 +246,79 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e)
cJSON_Delete(dynamic_policy);
}
- break;
- CASE(OGS_SBI_HTTP_METHOD_PUT)
- if (message->h.resource.component[1] && !message->h.resource.component[2])
- {
+ break;
+ CASE(OGS_SBI_HTTP_METHOD_PUT)
+ if (message->h.resource.component[1] && !message->h.resource.component[2])
+ {
msaf_api_dynamic_policy_t *dynamic_policy;
msaf_dynamic_policy_t *msaf_dynamic_policy = NULL;
- cJSON *dynamic_policy_received;
- const char *reason;
+ cJSON *dynamic_policy_received;
+ const char *reason;
- if(!check_http_content_type(request->http,"application/json")){
+ if (!check_http_content_type(request->http,"application/json")) {
ogs_assert(true == nf_server_send_error(stream, 415, 1, message, "Unsupported Media Type.", "Expected content type: application/json", NULL, m5_dynamicpolicy_api, app_meta));
ogs_sbi_message_free(message);
ogs_free(message);
return;
}
- if(!request->http.content) {
+ if (!request->http.content) {
ogs_assert(true == nf_server_send_error(stream, 400, 1, message, "Bad request.", "Request has no content", NULL, m5_dynamicpolicy_api, app_meta));
ogs_sbi_message_free(message);
ogs_free(message);
- return;
+ return;
}
- dynamic_policy_received = cJSON_Parse(request->http.content);
+ dynamic_policy_received = cJSON_Parse(request->http.content);
dynamic_policy = msaf_api_dynamic_policy_parseRequestFromJSON(dynamic_policy_received, &reason);
if (!dynamic_policy) {
- char *err;
- err = ogs_msprintf("Badly formed Dynamic Policy [%s]", reason);
+ char *err;
+ err = ogs_msprintf("Badly formed Dynamic Policy [%s]", reason);
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, 1, message, "Malformed request body", err, NULL, m5_dynamicpolicy_api, app_meta));
ogs_free(err);
break;
}
- /*
- if(strcmp(message->h.resource.component[1], dynamic_policy->dynamic_policy_id)){
+ /*
+ if (strcmp(message->h.resource.component[1], dynamic_policy->dynamic_policy_id)) {
const char *err = "Updating dynamic policy: The path component and the JSON body have mismatching Dynamic policy id";
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 400, 1, message, "Updating dynamic policy failed.",
err, NULL, m5_dynamicpolicy_api, app_meta));
break;
- }
- */
+ }
+ */
- msaf_dynamic_policy = msaf_dynamic_policy_find_by_dynamicPolicyId(message->h.resource.component[1]);
- if(!msaf_dynamic_policy) {
- const char *err = "Updating dynamic policy: Dynamic policy not found";
+ msaf_dynamic_policy = msaf_dynamic_policy_find_by_dynamicPolicyId(message->h.resource.component[1]);
+ if (!msaf_dynamic_policy) {
+ const char *err = "Updating dynamic policy: Dynamic policy not found";
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 404, 1, message, "Updating dynamic policy failed.",
err, NULL, m5_dynamicpolicy_api, app_meta));
break;
-
- }
-
- if(dynamic_policy->dynamic_policy_id) ogs_free(dynamic_policy->dynamic_policy_id);
- dynamic_policy->dynamic_policy_id = msaf_strdup(message->h.resource.component[1]);
-
- if(!msaf_dynamic_policy_update_pcf(msaf_dynamic_policy, dynamic_policy)) {
- const char *err = "Updating dynamic policy: Dynamic policy not found";
+
+ }
+
+ if (dynamic_policy->dynamic_policy_id) ogs_free(dynamic_policy->dynamic_policy_id);
+ dynamic_policy->dynamic_policy_id = msaf_strdup(message->h.resource.component[1]);
+
+ if (!msaf_dynamic_policy_update_pcf(msaf_dynamic_policy, dynamic_policy)) {
+ const char *err = "Updating dynamic policy: Dynamic policy not found";
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 404, 1, message, "Updating dynamic policy failed.",
err, NULL, m5_dynamicpolicy_api, app_meta));
break;
- } else {
+ } else {
ogs_sbi_response_t *response;
int response_code = 200;
char *body;
- char *hash;
- cJSON *dyn_policy;
+ char *hash;
+ cJSON *dyn_policy;
- dyn_policy = msaf_api_dynamic_policy_convertResponseToJSON((const msaf_api_dynamic_policy_t *)msaf_dynamic_policy->DynamicPolicy);
+ dyn_policy = msaf_api_dynamic_policy_convertResponseToJSON((const msaf_api_dynamic_policy_t *)msaf_dynamic_policy->DynamicPolicy);
body = cJSON_Print(dyn_policy);
hash= calculate_hash(body);
@@ -318,30 +328,30 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e)
0,
NULL, m5_dynamicpolicy_api, app_meta);
ogs_assert(response);
- nf_server_populate_response(response, strlen(body), ogs_strdup(body), response_code);
+ nf_server_populate_response(response, strlen(body), msaf_strdup(body), response_code);
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
ogs_free(hash);
cJSON_Delete(dyn_policy);
cJSON_free(body);
-
- }
+ }
- cJSON_Delete(dynamic_policy_received);
+ cJSON_Delete(dynamic_policy_received);
-
- }
- break;
+
+
+ }
+ break;
CASE(OGS_SBI_HTTP_METHOD_OPTIONS)
- if (message->h.resource.component[1] && !message->h.resource.component[2]) {
- msaf_dynamic_policy_t *msaf_dynamic_policy;
- ogs_sbi_response_t *response;
- char *methods = NULL;
- msaf_dynamic_policy = msaf_dynamic_policy_find_by_dynamicPolicyId(message->h.resource.component[1]);
- if(!msaf_dynamic_policy) {
+ if (message->h.resource.component[1] && !message->h.resource.component[2]) {
+ msaf_dynamic_policy_t *msaf_dynamic_policy;
+ ogs_sbi_response_t *response;
+ char *methods = NULL;
+ msaf_dynamic_policy = msaf_dynamic_policy_find_by_dynamicPolicyId(message->h.resource.component[1]);
+ if (!msaf_dynamic_policy) {
const char *err = "OPTIONS: Dynamic policy not found";
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 404, 1, message, "Dynamic policy failed.",
@@ -349,119 +359,119 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e)
break;
}
- 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, m5_dynamicpolicy_api, app_meta);
+ 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, m5_dynamicpolicy_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 {
-
- ogs_sbi_response_t *response;
- char *methods = NULL;
+ if (methods) ogs_free(methods);
+ } else {
+
+ ogs_sbi_response_t *response;
+ char *methods = NULL;
- methods = ogs_msprintf("%s, %s",OGS_SBI_HTTP_METHOD_POST, OGS_SBI_HTTP_METHOD_OPTIONS);
+ 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, m5_dynamicpolicy_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);
+ if (methods) ogs_free(methods);
}
- break;
-
- DEFAULT
+ 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;
-
- CASE("network-assistance")
+
+ CASE("network-assistance")
SWITCH(message->h.method)
- CASE(OGS_SBI_HTTP_METHOD_DELETE)
- if(message->h.resource.component[1])
+ CASE(OGS_SBI_HTTP_METHOD_DELETE)
+ if (message->h.resource.component[1])
{
- msaf_network_assistance_session_t *na_sess = NULL;
- na_sess = msaf_network_assistance_session_retrieve((const char *)message->h.resource.component[1]);
- if(na_sess){
- ogs_sbi_response_t *response;
+ msaf_network_assistance_session_t *na_sess = NULL;
+ na_sess = msaf_network_assistance_session_retrieve((const char *)message->h.resource.component[1]);
+ if (na_sess) {
+ ogs_sbi_response_t *response;
response = nf_server_new_response(NULL, NULL, 0, NULL, 0, NULL, m5_networkassistance_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_network_assistance_session_delete_by_session_id((const char *)message->h.resource.component[1]);
- } else {
- char *err = NULL;
+ } else {
+ char *err = NULL;
err = ogs_msprintf("The AF has no network assistance session with id [%s].", message->h.resource.component[1]);
ogs_error("%s", err);
- ogs_assert(true == nf_server_send_error(stream, 404, 0, message, "Unable to retrieve the Network Assistance Session", err, NULL, m5_networkassistance_api, app_meta));
+ ogs_assert(true == nf_server_send_error(stream, 404, 0, message, "Unable to retrieve the Network Assistance Session", err, NULL, m5_networkassistance_api, app_meta));
ogs_free(err);
- }
+ }
- } else {
- ogs_assert(true == nf_server_send_error(stream, 400, 0, message, "Unable to retrieve the Network Assistance Session", "Session Id not present in the request", NULL, m5_networkassistance_api, app_meta));
-
- }
- break;
+ } else {
+ ogs_assert(true == nf_server_send_error(stream, 400, 0, message, "Unable to retrieve the Network Assistance Session", "Session Id not present in the request", NULL, m5_networkassistance_api, app_meta));
+ }
+ break;
- CASE(OGS_SBI_HTTP_METHOD_GET)
- if(message->h.resource.component[1])
- {
- cJSON *network_assistance_sess;
- network_assistance_sess = msaf_network_assistance_session_get_json((const char *)message->h.resource.component[1]);
- if(network_assistance_sess) {
- msaf_network_assistance_session_t *na_sess = NULL;
- ogs_sbi_response_t *response;
- int response_code = 200;
- char *body;
- char *hash;
+ CASE(OGS_SBI_HTTP_METHOD_GET)
+ if (message->h.resource.component[1])
+ {
+
+ cJSON *network_assistance_sess;
+ network_assistance_sess = msaf_network_assistance_session_get_json((const char *)message->h.resource.component[1]);
+ if (network_assistance_sess) {
+ msaf_network_assistance_session_t *na_sess = NULL;
+ ogs_sbi_response_t *response;
+ int response_code = 200;
+ char *body;
+ char *hash;
- body = cJSON_Print(network_assistance_sess);
- hash= calculate_hash(body);
+ body = cJSON_Print(network_assistance_sess);
+ hash= calculate_hash(body);
- na_sess = msaf_network_assistance_session_retrieve((const char *)message->h.resource.component[1]);
+ na_sess = msaf_network_assistance_session_retrieve((const char *)message->h.resource.component[1]);
- response = nf_server_new_response(request->h.uri, "application/json",
+ response = nf_server_new_response(request->h.uri, "application/json",
na_sess->na_sess_created, hash,
- msaf_self()->config.server_response_cache_control->m5_service_access_information_response_max_age,
+ msaf_self()->config.server_response_cache_control->m5_service_access_information_response_max_age,
NULL, m5_networkassistance_api, app_meta);
- ogs_assert(response);
- nf_server_populate_response(response, strlen(body), ogs_strdup(body), response_code);
+ ogs_assert(response);
+ nf_server_populate_response(response, strlen(body), msaf_strdup(body), response_code);
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
- ogs_free(hash);
-
- cJSON_Delete(network_assistance_sess);
- cJSON_free(body);
+ ogs_free(hash);
+
+ cJSON_Delete(network_assistance_sess);
+ cJSON_free(body);
- } else {
+ } else {
char *err = NULL;
err = ogs_msprintf("The AF has no network assistance session with id [%s].", message->h.resource.component[1]);
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 404, 0, message, "Unable to retrieve the Network Assistance Session", err, NULL, m5_networkassistance_api, app_meta));
- ogs_free(err);
- }
+ ogs_free(err);
+ }
+
+ } else {
- } else {
-
ogs_assert(true == nf_server_send_error(stream, 400, 0, message, "Unable to retrieve the Network Assistance Session", "Session Id not present in the request", NULL, m5_networkassistance_api, app_meta));
- }
- break;
+ }
+ break;
- CASE(OGS_SBI_HTTP_METHOD_PUT)
- if(message->h.resource.component[1] && !message->h.resource.component[2])
+ CASE(OGS_SBI_HTTP_METHOD_PUT)
+ if (message->h.resource.component[1] && !message->h.resource.component[2])
{
msaf_network_assistance_session_t *na_sess;
- cJSON *network_assistance_sess;
- msaf_api_network_assistance_session_t *nas;
+ cJSON *network_assistance_sess;
+ msaf_api_network_assistance_session_t *nas;
- if(!check_http_content_type(request->http,"application/json")){
+ if (!check_http_content_type(request->http,"application/json")) {
ogs_assert(true == nf_server_send_error(stream, 415, 3, message, "Unsupported Media Type.", "Expected content type: application/json", NULL, m5_networkassistance_api, app_meta));
ogs_sbi_message_free(message);
ogs_free(message);
@@ -476,15 +486,15 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e)
ogs_assert(true == nf_server_send_error(stream, 400, 0, message, "Creation of the Network Assistance Session failed.", err, NULL, m5_networkassistance_api, app_meta));
break;
}
-
- nas = msaf_api_network_assistance_session_parseRequestFromJSON(network_assistance_sess, NULL);
- if(nas->na_session_id) {
- ogs_free(nas->na_session_id);
- nas->na_session_id = message->h.resource.component[1];
- }
+
+ nas = msaf_api_network_assistance_session_parseRequestFromJSON(network_assistance_sess, NULL);
+ if (nas->na_session_id) {
+ ogs_free(nas->na_session_id);
+ nas->na_session_id = message->h.resource.component[1];
+ }
na_sess = msaf_network_assistance_session_retrieve((const char *)message->h.resource.component[1]);
- if(!na_sess){
+ if (!na_sess) {
char *err = NULL;
err = ogs_msprintf("The AF has no network assistance session with id [%s].", message->h.resource.component[1]);
ogs_error("%s", err);
@@ -494,20 +504,20 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e)
break;
}
- if(!msaf_nw_assistance_session_update(na_sess, nas)) {
- const char *err = "Updating dynamic policy: Unable to communicate withe the PCF";
+ if (!msaf_nw_assistance_session_update(na_sess, nas)) {
+ const char *err = "Updating dynamic policy: Unable to communicate withe the PCF";
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 404, 1, message, "Updating dynamic policy failed.",
err, NULL, m5_networkassistance_api, app_meta));
break;
- } else {
+ } else {
ogs_sbi_response_t *response;
int response_code = 200;
char *body;
- char *hash;
- cJSON *nw_assist_session;
+ char *hash;
+ cJSON *nw_assist_session;
- nw_assist_session = msaf_api_network_assistance_session_convertResponseToJSON((const msaf_api_network_assistance_session_t *)na_sess->NetworkAssistanceSession);
+ nw_assist_session = msaf_api_network_assistance_session_convertResponseToJSON((const msaf_api_network_assistance_session_t *)na_sess->NetworkAssistanceSession);
body = cJSON_Print(nw_assist_session);
hash = calculate_hash(body);
@@ -517,95 +527,95 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e)
0,
NULL, m5_networkassistance_api, app_meta);
ogs_assert(response);
- nf_server_populate_response(response, strlen(body), ogs_strdup(body), response_code);
+ nf_server_populate_response(response, strlen(body), msaf_strdup(body), response_code);
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
ogs_free(hash);
cJSON_Delete(nw_assist_session);
cJSON_free(body);
- }
+ }
+
+ cJSON_Delete(network_assistance_sess);
- cJSON_Delete(network_assistance_sess);
-
- }
- break;
+ }
+ break;
CASE(OGS_SBI_HTTP_METHOD_POST)
- if(message->h.resource.component[1] && !strcmp(message->h.resource.component[2], "boost-request"))
+ if (message->h.resource.component[1] && !strcmp(message->h.resource.component[2], "boost-request"))
{
- msaf_network_assistance_session_t *na_sess;
- na_sess = msaf_network_assistance_session_retrieve((const char *)message->h.resource.component[1]);
- if(!na_sess){
- char *err = NULL;
+ msaf_network_assistance_session_t *na_sess;
+ na_sess = msaf_network_assistance_session_retrieve((const char *)message->h.resource.component[1]);
+ if (!na_sess) {
+ char *err = NULL;
err = ogs_msprintf("The AF has no network assistance session with id [%s].", message->h.resource.component[1]);
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 404, 0, message, "Unable to retrieve the Network Assistance Session", err, NULL, m5_networkassistance_api, app_meta));
ogs_free(err);
- }
- if(!is_ue_allowed_to_request_delivery_boost(na_sess)) {
- char *reason = NULL;
- msaf_api_operation_success_response_t *operation_success_response;
- cJSON *op_success_response;
- char *success_response;
- ogs_sbi_response_t *response;
+ }
+ if (!is_ue_allowed_to_request_delivery_boost(na_sess)) {
+ char *reason = NULL;
+ msaf_api_operation_success_response_t *operation_success_response;
+ cJSON *op_success_response;
+ char *success_response;
+ ogs_sbi_response_t *response;
int response_code = 200;
reason = ogs_msprintf("The AF has an active delivery boost for the network assistance session [%s].", message->h.resource.component[1]);
ogs_debug("%s", reason);
-
- operation_success_response = msaf_api_operation_success_response_create(reason, 0);
- op_success_response = msaf_api_operation_success_response_convertResponseToJSON(operation_success_response);
- success_response = cJSON_Print(op_success_response);
- response = nf_server_new_response(NULL, "application/json", 0, NULL, 0, NULL, m5_networkassistance_api, app_meta);
+ operation_success_response = msaf_api_operation_success_response_create(reason, 0);
+ op_success_response = msaf_api_operation_success_response_convertResponseToJSON(operation_success_response);
+ success_response = cJSON_Print(op_success_response);
+
+ response = nf_server_new_response(NULL, "application/json", 0, NULL, 0, NULL, m5_networkassistance_api, app_meta);
ogs_assert(response);
- nf_server_populate_response(response, strlen(success_response), ogs_strdup(success_response), response_code);
+ nf_server_populate_response(response, strlen(success_response), msaf_strdup(success_response), response_code);
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
- cJSON_Delete(op_success_response);
- cJSON_free(success_response);
- //ogs_free(reason);
- msaf_api_operation_success_response_free(operation_success_response);
- break;
+ cJSON_Delete(op_success_response);
+ cJSON_free(success_response);
+ //ogs_free(reason);
+ msaf_api_operation_success_response_free(operation_success_response);
+ break;
- }
+ }
- nw_assist_event = (msaf_event_t*)populate_msaf_event_with_metadata(e, m5_networkassistance_api, app_meta);
- msaf_nw_assistance_session_delivery_boost_update(na_sess, nw_assist_event);
+ nw_assist_event = (msaf_event_t*)populate_msaf_event_with_metadata(e, m5_networkassistance_api, app_meta);
+ msaf_nw_assistance_session_delivery_boost_update(na_sess, nw_assist_event);
- } else {
-
- cJSON *network_assistance_sess;
- cJSON *service_data_flow_descriptions = NULL;
- cJSON *policy_template_id = NULL;
- cJSON *requested_qos = NULL;
- cJSON *provisioning_session_id = NULL;
+ } else {
- if(!check_http_content_type(request->http,"application/json")){
- ogs_assert(true == nf_server_send_error(stream, 415, 3, message, "Unsupported Media Type.", "Expected content type: application/json", NULL, m5_networkassistance_api, app_meta));
+ cJSON *network_assistance_sess;
+ cJSON *service_data_flow_descriptions = NULL;
+ cJSON *policy_template_id = NULL;
+ cJSON *requested_qos = NULL;
+ cJSON *provisioning_session_id = NULL;
+
+ if (!check_http_content_type(request->http,"application/json")) {
+ ogs_assert(true == nf_server_send_error(stream, 415, 3, message, "Unsupported Media Type.", "Expected content type: application/json", NULL, m5_networkassistance_api, app_meta));
ogs_sbi_message_free(message);
ogs_free(message);
- }
+ }
ogs_debug("Request body: %s", request->http.content);
network_assistance_sess = cJSON_Parse(request->http.content);
- if (!network_assistance_sess) {
+ if (!network_assistance_sess) {
const char *err = "networkAssistanceSession: Could not parse request body as JSON";
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 400, 0, message, "Creation of the Network Assistance Session failed.", err, NULL, m5_networkassistance_api, app_meta));
break;
- }
+ }
- service_data_flow_descriptions = cJSON_GetObjectItemCaseSensitive(network_assistance_sess, "serviceDataFlowDescriptions");
+ service_data_flow_descriptions = cJSON_GetObjectItemCaseSensitive(network_assistance_sess, "serviceDataFlowDescriptions");
if (!service_data_flow_descriptions) {
const char *err = "createNetworkAssistanceSession: \"serviceDataFlowDescriptions\" not present";
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 400, 0, message, "Creation of the Network Assistance Session failed.", err, NULL, m5_networkassistance_api, app_meta));
- cJSON_Delete(network_assistance_sess);
+ cJSON_Delete(network_assistance_sess);
break;
}
if (!cJSON_IsArray(service_data_flow_descriptions)) {
@@ -613,31 +623,31 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e)
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 400, 0, message, "Creation of the Network Assistance Session failed.", err, NULL, m5_networkassistance_api, app_meta));
cJSON_Delete(network_assistance_sess);
- break;
+ break;
}
- provisioning_session_id = cJSON_GetObjectItemCaseSensitive(network_assistance_sess, "provisioningSessionId");
- if(!provisioning_session_id) {
- const char *err = "createNetworkAssistanceSession: \"provisioningSessionId\" is not present";
+ provisioning_session_id = cJSON_GetObjectItemCaseSensitive(network_assistance_sess, "provisioningSessionId");
+ if (!provisioning_session_id) {
+ const char *err = "createNetworkAssistanceSession: \"provisioningSessionId\" is not present";
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 400, 0, message, "Creation of the Network Assistance Session failed.", err, NULL, m5_networkassistance_api, app_meta));
cJSON_Delete(network_assistance_sess);
break;
-
- }
- if (!cJSON_IsString(provisioning_session_id)) {
- const char *err = "createNetworkAssistanceSession: \"provisioningSessionId\" is not a string";
+
+ }
+ if (!cJSON_IsString(provisioning_session_id)) {
+ const char *err = "createNetworkAssistanceSession: \"provisioningSessionId\" is not a string";
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 400, 0, message, "Creation of the Network Assistance Session failed.", err, NULL, m5_networkassistance_api, app_meta));
cJSON_Delete(network_assistance_sess);
break;
-
- }
+
+ }
policy_template_id = cJSON_GetObjectItemCaseSensitive(network_assistance_sess, "policyTemplateId");
if (!policy_template_id) {
ogs_debug("createNetworkAssistanceSession: \"policyTemplateId\" is not present");
-
+
}
if (!policy_template_id && cJSON_IsString(policy_template_id)) {
ogs_debug("createNetworkAssistanceSession: \"policyTemplateId\" is not a string");
@@ -647,10 +657,10 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e)
if (!requested_qos) {
ogs_debug("createNetworkAssistanceSession: \"requestedQoS\" is not present");
}
-
- nw_assist_event = (msaf_event_t*)populate_msaf_event_with_metadata(e, m5_networkassistance_api, app_meta);
- if(!msaf_nw_assistance_session_create(network_assistance_sess, nw_assist_event)) {
+ nw_assist_event = (msaf_event_t*)populate_msaf_event_with_metadata(e, m5_networkassistance_api, app_meta);
+
+ if (!msaf_nw_assistance_session_create(network_assistance_sess, nw_assist_event)) {
const char *err = "Problem in obtaining the information required to create the Network Assitance Session";
ogs_error("%s", err);
@@ -658,18 +668,18 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e)
cJSON_Delete(network_assistance_sess);
break;
- }
+ }
- cJSON_Delete(network_assistance_sess);
- }
- break;
- DEFAULT
+ cJSON_Delete(network_assistance_sess);
+ }
+ 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;
-
+
CASE("service-access-information")
SWITCH(message->h.method)
CASE(OGS_SBI_HTTP_METHOD_GET)
@@ -718,7 +728,7 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e)
ogs_sbi_response_t *response;
response = nf_server_new_response(NULL, "application/json", ogs_time_sec(sai_entry->generated)+1, sai_entry->hash, msaf_self()->config.server_response_cache_control->m5_service_access_information_response_max_age, NULL, m5_serviceaccessinformation_api, app_meta);
ogs_assert(response);
- nf_server_populate_response(response, response_body?strlen(response_body):0, ogs_strdup(response_body), response_code);
+ nf_server_populate_response(response, response_body?strlen(response_body):0, msaf_strdup(response_body), response_code);
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
}
break;
@@ -739,6 +749,106 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e)
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;
+
+ CASE("metrics-reporting")
+ 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 *provisioning_session;
+ provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(message->h.resource.component[1]);
+
+ if(provisioning_session){
+ if (ogs_hash_count(provisioning_session->metrics_reporting_map) == 0) {
+ char *err;
+ err = ogs_msprintf("No MetricsReportingConfiguration for Provisioning Session [%s]", message->h.resource.component[1]);
+ ogs_error("%s", err);
+ ogs_assert(true==nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_NOT_FOUND, 1, message, "Not found", err, NULL, m5_metricsreporting_api, app_meta));
+ ogs_free(err);
+ } else {
+ const char *content_type = "application/xml";
+ 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)) {
+ content_type = ogs_hash_this_val(hi);
+ break;
+ }
+ }
+
+ SWITCH(content_type)
+ CASE("application/xml")
+
+ /* This will parse relevant information from incoming XML */
+ char *parseXmlField(const char *xmlString, const char *fieldName) {
+ char *startTag = malloc(strlen(fieldName) + 3);
+ char *endTag = "\"";
+ sprintf(startTag, "%s=\"", fieldName);
+ char *startPosition = strstr(xmlString, startTag), *endPosition, *fieldValue = NULL;
+ if (startPosition && (endPosition = strstr(startPosition += strlen(startTag), endTag))) {
+ fieldValue = strndup(startPosition, endPosition - startPosition);
+ }
+ free(startTag);
+ return fieldValue;
+ }
+ if (request->http.content) {
+ char *reportTime = parseXmlField(request->http.content, "reportTime");
+ char *recordingSessionId = parseXmlField(request->http.content, "recordingSessionId");
+ char *clientId = parseXmlField(request->http.content, "clientID");
+
+ if (msaf_data_collection_store(message->h.resource.component[1], "metrics_reports", clientId, recordingSessionId, reportTime, "xml", request->http.content)) {
+ ogs_sbi_response_t *response;
+ response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, NULL,m5_metricsreporting_api, app_meta);
+ ogs_assert(response);
+ nf_server_populate_response(response, 0, NULL, 204);
+ ogs_assert(true == ogs_sbi_server_send_response(stream, response));
+ } else {
+ char *err;
+ err = ogs_msprintf( "Failed to store Metrics Report for provisioning session [%s]", message->h.resource.component[1]);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR, 1, message, "Data storage error", err, NULL, m5_metricsreporting_api, app_meta));
+ ogs_free(err);
+ }
+ break;
+ DEFAULT
+ char *err;
+ err = ogs_msprintf( "Unrecognised content type for Metrics Report for Provisioning Session [%s]", message->h.resource.component[1]);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, 1, message, "Unsupported Media Type",err, NULL, m5_metricsreporting_api, app_meta));
+ ogs_free(err);
+ END
+ }
+ }
+ } else{
+ char *err;
+ err = ogs_msprintf("Provisioning session [%s] not found for Metrics Report", message->h.resource.component[1]);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_NOT_FOUND, 1, message, "Not Found", err, NULL, m5_metricsreporting_api, app_meta));
+ ogs_free(err);
+ }
+ } else {
+ ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_NOT_FOUND, 0, message, "No Metrics ID Found", NULL, NULL, m5_metricsreporting_api, app_meta));
+ }
+ break;
+ CASE(OGS_SBI_HTTP_METHOD_OPTIONS)
+ if (message->h.resource.component[1] && message->h.resource.component[2] && !message->h.resource.component[3]) {
+ ogs_sbi_response_t *response;
+ response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0, OGS_SBI_HTTP_METHOD_POST ", " OGS_SBI_HTTP_METHOD_OPTIONS, m5_metricsreporting_api, app_meta);
+ ogs_assert(response);
+ nf_server_populate_response(response, 0, NULL, 204);
+ ogs_assert(true == ogs_sbi_server_send_response(stream, response));
+ } else {
+ ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_NOT_FOUND, 2, message, "No Metrics ID Found", message->h.method, NULL, m5_metricsreporting_api, app_meta));
+ }
+ DEFAULT
+ char *err;
+ err = ogs_msprintf("Method [%s] not implemented for M5 Metrics Reporting API", message->h.method);
+ ogs_error("%s", err);
+ ogs_assert(true == nf_server_send_error(stream, OGS_SBI_HTTP_STATUS_MEHTOD_NOT_ALLOWED, 1, message, "Method Not Allowed", err, NULL, m5_metricsreporting_api, app_meta));
+ ogs_free(err);
+ END
+ break;
+ DEFAULT
+
CASE("consumption-reporting")
SWITCH(message->h.method)
CASE(OGS_SBI_HTTP_METHOD_POST)
@@ -843,6 +953,7 @@ void msaf_m5_state_functional(ogs_fsm_t *s, msaf_event_t *e)
}
break;
CASE(OGS_SBI_HTTP_METHOD_OPTIONS)
+
if (message->h.resource.component[1] && !message->h.resource.component[2]) {
ogs_sbi_response_t *response;
response = nf_server_new_response(request->h.uri, NULL, 0, NULL, 0,
@@ -904,7 +1015,7 @@ static bool is_dynamic_policy_create_request_valid(ogs_sbi_request_t *request, o
cJSON *policy_template_id = NULL;
cJSON *provisioning_session_id = NULL;
- if(!check_http_content_type(request->http,"application/json")){
+ if (!check_http_content_type(request->http,"application/json")) {
ogs_assert(true == nf_server_send_error(stream, 415, 3, message, "Unsupported Media Type.",
"Expected content type: application/json", NULL, m5_dynamicpolicy_api, app_meta));
ogs_sbi_message_free(message);
@@ -938,7 +1049,7 @@ static bool is_dynamic_policy_create_request_valid(ogs_sbi_request_t *request, o
}
provisioning_session_id = cJSON_GetObjectItemCaseSensitive(dynamic_policy, "provisioningSessionId");
- if(!provisioning_session_id) {
+ if (!provisioning_session_id) {
const char *err = "createDynamicPolicy: \"provisioningSessionId\" is not present";
ogs_error("%s", err);
ogs_assert(true == nf_server_send_error(stream, 400, 0, message, "Creation of the Dynamic Policy failed.", err, NULL, m5_dynamicpolicy_api, app_meta));
@@ -972,7 +1083,7 @@ static bool is_dynamic_policy_create_request_valid(ogs_sbi_request_t *request, o
return 0;
}
- if(dynamic_policy) {
+ if (dynamic_policy) {
cJSON_Delete(dynamic_policy);
dynamic_policy = NULL;
}
diff --git a/src/5gmsaf/msaf-m5-sm.h b/src/5gmsaf/msaf-m5-sm.h
index 26400a8..552e888 100644
--- a/src/5gmsaf/msaf-m5-sm.h
+++ b/src/5gmsaf/msaf-m5-sm.h
@@ -1,11 +1,11 @@
/*
-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
+ * 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 MSAF_M5_SM_H
diff --git a/src/5gmsaf/msaf-mgmt-sm.c b/src/5gmsaf/msaf-mgmt-sm.c
index 9f2ea08..6baadab 100644
--- a/src/5gmsaf/msaf-mgmt-sm.c
+++ b/src/5gmsaf/msaf-mgmt-sm.c
@@ -1,6 +1,6 @@
/*
* License: 5G-MAG Public License (v1.0)
- * Author: Dev Audsin
+ * Author: Dev Audsin
* Copyright: (C) 2023 British Broadcasting Corporation
*
* For full license terms please see the LICENSE file distributed with this
@@ -17,7 +17,7 @@
#include "msaf-version.h"
#include "msaf-sm.h"
#include "openapi/api/Maf_ManagementAPI-info.h"
-
+
#include "msaf-mgmt-sm.h"
static const nf_server_interface_metadata_t
@@ -75,7 +75,7 @@ void msaf_maf_mgmt_state_functional(ogs_fsm_t *s, msaf_event_t *e)
ogs_fsm_dispatch(&msaf_self()->msaf_fsm.msaf_m1_sm, e);
message = NULL;
break;
-
+
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));
diff --git a/src/5gmsaf/msaf-mgmt-sm.h b/src/5gmsaf/msaf-mgmt-sm.h
index c3f0469..7adbbf8 100644
--- a/src/5gmsaf/msaf-mgmt-sm.h
+++ b/src/5gmsaf/msaf-mgmt-sm.h
@@ -1,11 +1,11 @@
/*
-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
+ * 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 MSAF_MGMT_SM_H
diff --git a/src/5gmsaf/msaf-sm.c b/src/5gmsaf/msaf-sm.c
index 321d398..6d822a1 100644
--- a/src/5gmsaf/msaf-sm.c
+++ b/src/5gmsaf/msaf-sm.c
@@ -1,7 +1,8 @@
/*
* License: 5G-MAG Public License (v1.0)
- * Author: Dev Audsin
- * Copyright: (C) 2022-2023 British Broadcasting Corporation
+ * Authors: Dev Audsin
+ * David Waring
+ * Copyright: (C) 2022-2024 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
@@ -81,7 +82,7 @@ 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, "*")){
+ if (!strcmp(request->h.method, OGS_SBI_HTTP_METHOD_OPTIONS) && !strcmp(request->h.uri, "*")) {
char *methods = NULL;
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);
@@ -138,7 +139,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e)
break;
CASE("3gpp-m1")
- if(check_event_addresses(e, msaf_self()->config.servers[MSAF_SVR_M1].ipv4, msaf_self()->config.servers[MSAF_SVR_M1].ipv6)){
+ if (check_event_addresses(e, msaf_self()->config.servers[MSAF_SVR_M1].ipv4, msaf_self()->config.servers[MSAF_SVR_M1].ipv6)) {
e->message = message;
message = NULL;
ogs_fsm_dispatch(&msaf_self()->msaf_fsm.msaf_m1_sm, e);
@@ -149,9 +150,9 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e)
ogs_free(error);
}
break;
-
+
CASE("5gmag-rt-management")
- if(check_event_addresses(e, msaf_self()->config.servers[MSAF_SVR_MSAF].ipv4, msaf_self()->config.servers[MSAF_SVR_MSAF].ipv6)){
+ if (check_event_addresses(e, msaf_self()->config.servers[MSAF_SVR_MSAF].ipv4, msaf_self()->config.servers[MSAF_SVR_MSAF].ipv6)) {
e->message = message;
message = NULL;
ogs_fsm_dispatch(&msaf_self()->msaf_fsm.msaf_maf_mgmt_sm, e);
@@ -162,10 +163,10 @@ 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);
}
- break;
+ break;
CASE("3gpp-m5")
- if(check_event_addresses(e, msaf_self()->config.servers[MSAF_SVR_M5].ipv4, msaf_self()->config.servers[MSAF_SVR_M5].ipv6)){
+ if (check_event_addresses(e, msaf_self()->config.servers[MSAF_SVR_M5].ipv4, msaf_self()->config.servers[MSAF_SVR_M5].ipv6)) {
e->message = message;
message = NULL;
ogs_fsm_dispatch(&msaf_self()->msaf_fsm.msaf_m5_sm, e);
@@ -198,7 +199,7 @@ 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")
/* M1 state machine handles M3 responses */
e->message = message;
@@ -210,13 +211,13 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e)
SWITCH(message->h.resource.component[0])
CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES)
- cJSON *nf_profile;
+ cJSON *nf_profile;
OpenAPI_nf_profile_t *nfprofile;
nf_instance = e->h.sbi.data;
ogs_assert(nf_instance);
- if (response->http.content_length && response->http.content){
+ if (response->http.content_length && response->http.content) {
ogs_debug( "response: %s", response->http.content);
nf_profile = cJSON_Parse(response->http.content);
nfprofile = OpenAPI_nf_profile_parseFromJSON(nf_profile);
@@ -233,7 +234,7 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e)
e->h.sbi.message = message;
//message = NULL;
ogs_fsm_dispatch(&nf_instance->sm, e);
- ogs_sbi_response_free(response);
+ ogs_sbi_response_free(response);
break;
CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS)
@@ -281,13 +282,13 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e)
break;
case MSAF_EVENT_DELIVERY_BOOST_TIMER:
- ogs_assert(e);
+ ogs_assert(e);
//e->message = message;
//message = NULL;
ogs_fsm_dispatch(&msaf_self()->msaf_fsm.msaf_m5_sm, e);
- break;
+ break;
- case OGS_EVENT_SBI_TIMER:
+ case OGS_EVENT_SBI_TIMER:
ogs_assert(e);
switch(e->h.timer_id) {
diff --git a/src/5gmsaf/msaf-sm.h b/src/5gmsaf/msaf-sm.h
index abef9eb..9c5cacf 100644
--- a/src/5gmsaf/msaf-sm.h
+++ b/src/5gmsaf/msaf-sm.h
@@ -1,11 +1,11 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-Copyright: (C) 2022-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
+ * License: 5G-MAG Public License (v1.0)
+ * Author: Dev Audsin
+ * Copyright: (C) 2022-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 MSAF_SM_H
diff --git a/src/5gmsaf/msaf.yaml.in b/src/5gmsaf/msaf.yaml.in
index d63e936..b04a75d 100644
--- a/src/5gmsaf/msaf.yaml.in
+++ b/src/5gmsaf/msaf.yaml.in
@@ -189,6 +189,7 @@ msaf:
serverResponseCacheControl:
- maxAge: 60
m1ProvisioningSessions: 60
+ m1MetricsReportingConfiguration: 60
m1ContentHostingConfigurations: 60
m1ServerCertificates: 60
m1ContentProtocols: 86400
diff --git a/src/5gmsaf/network-assistance-delivery-boost.c b/src/5gmsaf/network-assistance-delivery-boost.c
index c33ca5b..c1116a4 100644
--- a/src/5gmsaf/network-assistance-delivery-boost.c
+++ b/src/5gmsaf/network-assistance-delivery-boost.c
@@ -1,12 +1,13 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Authors: Dev Audsin
+ * David Waring
+ * Copyright: (C) 2023-2024 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 "network-assistance-delivery-boost.h"
@@ -35,12 +36,12 @@ void msaf_network_assistance_delivery_boost_free(void) {
}
int is_ue_allowed_to_request_delivery_boost(msaf_network_assistance_session_t *na_sess) {
-
- if(na_sess->active_delivery_boost)
- return 0;
+
+ if (na_sess->active_delivery_boost)
+ return 0;
//Placeholder to implement any further restrictions here
-
+
return 1;
}
diff --git a/src/5gmsaf/network-assistance-delivery-boost.h b/src/5gmsaf/network-assistance-delivery-boost.h
index 91fbcc5..5530eab 100644
--- a/src/5gmsaf/network-assistance-delivery-boost.h
+++ b/src/5gmsaf/network-assistance-delivery-boost.h
@@ -1,12 +1,12 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Author: Dev Audsin
+ * 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 MSAF_NETWORK_ASSISTANCE_DELIVERY_BOOST_H
#define MSAF_NETWORK_ASSISTANCE_DELIVERY_BOOST_H
@@ -20,7 +20,7 @@ program. If this file is missing then the license can be retrieved from
extern "C" {
#endif
-typedef struct msaf_network_assistance_session_s msaf_network_assistance_session_t;
+typedef struct msaf_network_assistance_session_s msaf_network_assistance_session_t;
typedef struct msaf_network_assistance_delivery_boost_s {
uint64_t delivery_boost_min_dl_bit_rate;
diff --git a/src/5gmsaf/network-assistance-session.c b/src/5gmsaf/network-assistance-session.c
index 9610540..650406f 100644
--- a/src/5gmsaf/network-assistance-session.c
+++ b/src/5gmsaf/network-assistance-session.c
@@ -1,12 +1,13 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Authors: Dev Audsin
+ * David Waring
+ * Copyright: (C) 2023-2024 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 "utilities.h"
#include "network-assistance-session.h"
@@ -59,7 +60,7 @@ int msaf_nw_assistance_session_create(cJSON *network_assistance_sess, msaf_event
OpenAPI_list_t *media_component = NULL;
nas = msaf_api_network_assistance_session_parseRequestFromJSON(network_assistance_sess, NULL);
- if(!nas) return 0;
+ if (!nas) return 0;
na_sess = msaf_network_assistance_session_init();
ogs_assert(na_sess);
@@ -75,26 +76,26 @@ int msaf_nw_assistance_session_create(cJSON *network_assistance_sess, msaf_event
service_data_flow_description = (msaf_api_service_data_flow_description_t *)node->data;
- if(service_data_flow_description->domain_name) {
- ogs_debug("Service Data Flow Descriptions specified using a domain name are not yet supported by this implementation");
+ if (service_data_flow_description->domain_name) {
+ ogs_debug("Service Data Flow Descriptions specified using a domain name are not yet supported by this implementation");
msaf_network_assistance_session_remove(na_sess);
- return 0;
- }
-
+ return 0;
+ }
+
- if(service_data_flow_description->flow_description && service_data_flow_description->domain_name) {
- ogs_error("Validation of service data flow description failed: Only one of flowDescription or domainName may be present");
+ if (service_data_flow_description->flow_description && service_data_flow_description->domain_name) {
+ ogs_error("Validation of service data flow description failed: Only one of flowDescription or domainName may be present");
msaf_network_assistance_session_remove(na_sess);
return 0;
- }
+ }
- if(!service_data_flow_description->flow_description && !service_data_flow_description->domain_name) {
+ if (!service_data_flow_description->flow_description && !service_data_flow_description->domain_name) {
ogs_error("Validation of service data flow description failed: flowDescription or domainName must be present");
msaf_network_assistance_session_remove(na_sess);
return 0;
}
- if(service_data_flow_description->flow_description){
+ if (service_data_flow_description->flow_description) {
if (!service_data_flow_description->flow_description->direction) {
ogs_error("Validation of service data flow description failed: no flowDescription.direction present");
@@ -148,7 +149,7 @@ int msaf_nw_assistance_session_create(cJSON *network_assistance_sess, msaf_event
}
ue_connection_details_free(ue_connection);
}
- }
+ }
}
return 1;
@@ -164,7 +165,7 @@ int msaf_nw_assistance_session_update(msaf_network_assistance_session_t *msaf_ne
ogs_assert(network_assistance_session);
if (!msaf_network_assistance_session->pcf_app_session) {
- ogs_error("The Network Assistance Session has no associated App Session");
+ ogs_error("The Network Assistance Session has no associated App Session");
return 0;
}
@@ -173,18 +174,18 @@ int msaf_nw_assistance_session_update(msaf_network_assistance_session_t *msaf_ne
service_data_flow_description = (msaf_api_service_data_flow_description_t *)node->data;
- if(service_data_flow_description->domain_name) {
+ if (service_data_flow_description->domain_name) {
ogs_debug("Service Data Flow Descriptions specified using a domain name are not yet supported by this implementation");
return 0;
}
- if(service_data_flow_description->flow_description && service_data_flow_description->domain_name) {
+ if (service_data_flow_description->flow_description && service_data_flow_description->domain_name) {
ogs_error("Validation of service data flow description failed: Exactly one of flowDescription or domainName must be present");
return 0;
}
- if(service_data_flow_description->flow_description){
+ if (service_data_flow_description->flow_description) {
if (!service_data_flow_description->flow_description->direction) {
ogs_error("The Network Assistance Session has direction in flow description");
@@ -193,18 +194,18 @@ int msaf_nw_assistance_session_update(msaf_network_assistance_session_t *msaf_ne
media_component = populate_media_component(network_assistance_session->policy_template_id, service_data_flow_description->flow_description, network_assistance_session->requested_qo_s, network_assistance_session->media_type?network_assistance_session->media_type: OpenAPI_media_type_VIDEO);
- if(!pcf_session_update_app_session(msaf_network_assistance_session->pcf_app_session, media_component)) {
+ if (!pcf_session_update_app_session(msaf_network_assistance_session->pcf_app_session, media_component)) {
ogs_error("Unable to send update request to the PCF");
return 0;
}
- }
- }
+ }
+ }
}
update_msaf_network_assistance_session_context(msaf_network_assistance_session, network_assistance_session);
return 1;
}
-void msaf_nw_assistance_session_delivery_boost_update(msaf_network_assistance_session_t *na_sess, msaf_event_t *e){
+void msaf_nw_assistance_session_delivery_boost_update(msaf_network_assistance_session_t *na_sess, msaf_event_t *e) {
OpenAPI_list_t *media_comps;
char *mir_bw_dl_bit_rate = NULL;
@@ -221,7 +222,7 @@ void msaf_nw_assistance_session_delivery_boost_update(msaf_network_assistance_se
add_delivery_boost_event_metadata_to_na_sess_context(na_sess, e);
- if(!pcf_session_update_app_session(na_sess->pcf_app_session, media_comps)) {
+ if (!pcf_session_update_app_session(na_sess->pcf_app_session, media_comps)) {
ogs_error("Unable to send update request to the PCF");
ogs_assert(true == nf_server_send_error(e->h.sbi.data, 401, 0, e->message, "Creation of delivery boost failed.", "Unable to send update request to the PCF" , NULL, e->nf_server_interface_metadata, e->app_meta));
}
@@ -235,7 +236,7 @@ void msaf_nw_assistance_session_delivery_boost_update(msaf_network_assistance_se
}
-void msaf_nw_assistance_session_update_pcf_on_timeout(msaf_network_assistance_session_t *na_sess){
+void msaf_nw_assistance_session_update_pcf_on_timeout(msaf_network_assistance_session_t *na_sess) {
OpenAPI_list_t *media_comps;
char *mir_bw_dl_bit_rate;
@@ -252,7 +253,7 @@ void msaf_nw_assistance_session_update_pcf_on_timeout(msaf_network_assistance_se
rv = pcf_session_update_app_session(na_sess->pcf_app_session, media_comps);
- if(!rv){
+ if (!rv) {
ogs_error("Unable to send update request to the PCF");
} else {
na_sess->active_delivery_boost = false;
@@ -273,10 +274,10 @@ msaf_network_assistance_session_t *msaf_network_assistance_session_retrieve(cons
msaf_network_assistance_session_t *na_sess = NULL;
ogs_list_for_each(&msaf_self()->network_assistance_sessions, na_sess)
{
- if(!strcmp(na_sess->naSessionId, na_session_id))
+ if (!strcmp(na_sess->naSessionId, na_session_id))
break;
}
- if(na_sess)
+ if (na_sess)
return na_sess;
return NULL;
@@ -288,10 +289,10 @@ cJSON *msaf_network_assistance_session_get_json(const char *na_session_id)
msaf_network_assistance_session_t *na_sess = NULL;
ogs_list_for_each(&msaf_self()->network_assistance_sessions, na_sess)
{
- if(!strcmp(na_sess->naSessionId, na_session_id))
+ if (!strcmp(na_sess->naSessionId, na_session_id))
break;
}
- if(na_sess)
+ if (na_sess)
return msaf_api_network_assistance_session_convertResponseToJSON(na_sess->NetworkAssistanceSession);
return NULL;
@@ -335,7 +336,7 @@ ue_network_identifier_t *populate_ue_connection_details(msaf_api_service_data_fl
void msaf_network_assistance_session_remove_all_pcf_app_session(void)
{
msaf_pcf_app_session_t *msaf_pcf_app_session = NULL, *next = NULL;
- ogs_list_for_each_safe(&msaf_self()->delete_pcf_app_sessions, next, msaf_pcf_app_session){
+ ogs_list_for_each_safe(&msaf_self()->delete_pcf_app_sessions, next, msaf_pcf_app_session) {
ogs_list_remove(&msaf_self()->delete_pcf_app_sessions, msaf_pcf_app_session);
ogs_free(msaf_pcf_app_session);
}
@@ -372,7 +373,7 @@ void msaf_network_assistance_session_remove_all()
{
msaf_network_assistance_session_t *msaf_network_assistance_session = NULL, *next = NULL;
- ogs_list_for_each_safe(&msaf_self()->network_assistance_sessions, next, msaf_network_assistance_session){
+ ogs_list_for_each_safe(&msaf_self()->network_assistance_sessions, next, msaf_network_assistance_session) {
ogs_list_remove(&msaf_self()->network_assistance_sessions, msaf_network_assistance_session);
msaf_network_assistance_session_remove(msaf_network_assistance_session);
}
@@ -382,8 +383,8 @@ void msaf_network_assistance_session_delete_by_session_id(const char *na_sess_id
{
msaf_network_assistance_session_t *msaf_network_assistance_session = NULL, *next = NULL;
- ogs_list_for_each_safe(&msaf_self()->network_assistance_sessions, next, msaf_network_assistance_session){
- if(!strcmp(msaf_network_assistance_session->naSessionId, na_sess_id)) {
+ ogs_list_for_each_safe(&msaf_self()->network_assistance_sessions, next, msaf_network_assistance_session) {
+ if (!strcmp(msaf_network_assistance_session->naSessionId, na_sess_id)) {
ogs_list_remove(&msaf_self()->network_assistance_sessions, msaf_network_assistance_session);
msaf_network_assistance_session_add_to_delete_list(msaf_network_assistance_session->pcf_app_session);
msaf_network_assistance_session_remove(msaf_network_assistance_session);
@@ -394,7 +395,7 @@ void msaf_network_assistance_session_delete_by_session_id(const char *na_sess_id
/*Private functions */
-static msaf_network_assistance_session_t *msaf_network_assistance_session_init(void){
+static msaf_network_assistance_session_t *msaf_network_assistance_session_init(void) {
msaf_network_assistance_session_t *na_sess;
na_sess = ogs_calloc(1, sizeof(msaf_network_assistance_session_t));
@@ -427,7 +428,7 @@ static OpenAPI_list_t *populate_media_component(char *policy_template_id, msaf_a
char *remote_addr;
char *remote_port;
- if(!strcmp(flow_description->direction, "UPLINK")){
+ if (!strcmp(flow_description->direction, "UPLINK")) {
remote_addr = flow_description->dst_ip?flow_description->dst_ip:"any";
remote_port = flow_description_port(flow_description->dst_port);
@@ -436,7 +437,7 @@ static OpenAPI_list_t *populate_media_component(char *policy_template_id, msaf_a
}
- if(!strcmp(flow_description->direction, "DOWNLINK")){
+ if (!strcmp(flow_description->direction, "DOWNLINK")) {
remote_addr = flow_description->src_ip?flow_description->src_ip:"any";
remote_port = flow_description_port(flow_description->src_port);
@@ -512,8 +513,8 @@ static void msaf_network_assistance_session_add_to_delete_list(pcf_app_session_t
static void msaf_network_assistance_session_remove_from_delete_list(void)
{
msaf_pcf_app_session_t *msaf_pcf_app_session = NULL, *next = NULL;
- ogs_list_for_each_safe(&msaf_self()->delete_pcf_app_sessions, next, msaf_pcf_app_session){
- if(!msaf_pcf_app_session->pcf_app_session){
+ ogs_list_for_each_safe(&msaf_self()->delete_pcf_app_sessions, next, msaf_pcf_app_session) {
+ if (!msaf_pcf_app_session->pcf_app_session) {
ogs_list_remove(&msaf_self()->delete_pcf_app_sessions, msaf_pcf_app_session);
ogs_free(msaf_pcf_app_session);
}
@@ -524,8 +525,8 @@ static void msaf_network_assistance_session_remove_from_delete_list(void)
static void msaf_pcf_app_session_free(void)
{
msaf_pcf_app_session_t *msaf_pcf_app_session;
- ogs_list_for_each(&msaf_self()->delete_pcf_app_sessions, msaf_pcf_app_session){
- if(msaf_pcf_app_session->pcf_app_session)
+ ogs_list_for_each(&msaf_self()->delete_pcf_app_sessions, msaf_pcf_app_session) {
+ if (msaf_pcf_app_session->pcf_app_session)
{
pcf_app_session_free(msaf_pcf_app_session->pcf_app_session);
msaf_pcf_app_session->pcf_app_session = NULL;
@@ -572,10 +573,10 @@ static ue_network_identifier_t *copy_ue_network_connection_identifier(const ue_n
ue_net_connection_copy = ogs_calloc(1, sizeof(ue_network_identifier_t));
if (ue_net_connection_copy) {
if (ue_net_connection->address) ogs_copyaddrinfo(&ue_net_connection_copy->address, ue_net_connection->address);
- if (ue_net_connection->supi) ue_net_connection_copy->supi = ogs_strdup(ue_net_connection->supi);
- if (ue_net_connection->gpsi) ue_net_connection_copy->gpsi = ogs_strdup(ue_net_connection->gpsi);
- if (ue_net_connection->dnn) ue_net_connection_copy->dnn = ogs_strdup(ue_net_connection->dnn);
- if (ue_net_connection->ip_domain) ue_net_connection_copy->ip_domain = ogs_strdup(ue_net_connection->ip_domain);
+ ue_net_connection_copy->supi = msaf_strdup(ue_net_connection->supi);
+ ue_net_connection_copy->gpsi = msaf_strdup(ue_net_connection->gpsi);
+ ue_net_connection_copy->dnn = msaf_strdup(ue_net_connection->dnn);
+ ue_net_connection_copy->ip_domain = msaf_strdup(ue_net_connection->ip_domain);
}
return ue_net_connection_copy;
}
@@ -591,21 +592,21 @@ static void free_ue_network_connection_identifier(ue_network_identifier_t *ue_ne
ogs_free(ue_net_connection);
}
-static void msaf_network_assistance_session_remove(msaf_network_assistance_session_t *msaf_network_assistance_session){
+static void msaf_network_assistance_session_remove(msaf_network_assistance_session_t *msaf_network_assistance_session) {
ogs_assert(msaf_network_assistance_session);
- if(msaf_network_assistance_session->naSessionId) {
+ if (msaf_network_assistance_session->naSessionId) {
ogs_free(msaf_network_assistance_session->naSessionId);
msaf_network_assistance_session->naSessionId = NULL;
}
- if(msaf_network_assistance_session->NetworkAssistanceSession) msaf_api_network_assistance_session_free(msaf_network_assistance_session->NetworkAssistanceSession);
- if(msaf_network_assistance_session->metadata){
- if(msaf_network_assistance_session->metadata->create_event) msaf_event_free(msaf_network_assistance_session->metadata->create_event);
- if(msaf_network_assistance_session->metadata->delivery_boost) msaf_event_free(msaf_network_assistance_session->metadata->delivery_boost);
+ if (msaf_network_assistance_session->NetworkAssistanceSession) msaf_api_network_assistance_session_free(msaf_network_assistance_session->NetworkAssistanceSession);
+ if (msaf_network_assistance_session->metadata) {
+ if (msaf_network_assistance_session->metadata->create_event) msaf_event_free(msaf_network_assistance_session->metadata->create_event);
+ if (msaf_network_assistance_session->metadata->delivery_boost) msaf_event_free(msaf_network_assistance_session->metadata->delivery_boost);
ogs_free(msaf_network_assistance_session->metadata);
}
- if(msaf_network_assistance_session->delivery_boost_timer)
+ if (msaf_network_assistance_session->delivery_boost_timer)
ogs_timer_delete(msaf_network_assistance_session->delivery_boost_timer);
ogs_free(msaf_network_assistance_session);
@@ -613,22 +614,22 @@ static void msaf_network_assistance_session_remove(msaf_network_assistance_sessi
}
static void ue_connection_details_free(ue_network_identifier_t *ue_connection) {
- if(ue_connection->address) ogs_freeaddrinfo(ue_connection->address);
- if(ue_connection->ip_domain) ogs_free(ue_connection->ip_domain);
+ if (ue_connection->address) ogs_freeaddrinfo(ue_connection->address);
+ if (ue_connection->ip_domain) ogs_free(ue_connection->ip_domain);
ogs_free(ue_connection);
}
-static bool app_session_change_callback(pcf_app_session_t *app_session, void *data){
+static bool app_session_change_callback(pcf_app_session_t *app_session, void *data) {
msaf_network_assistance_session_t *na_sess;
ogs_debug("change callback(app_session=%p, data=%p)", app_session, data);
na_sess = (msaf_network_assistance_session_t *)data;
- if(!app_session){
+ if (!app_session) {
- if(na_sess->metadata->create_event)
+ if (na_sess->metadata->create_event)
{
/*
ogs_assert(true == nf_server_send_error(na_sess->create_event->h.sbi.data, 401, 0, na_sess->create_event->message, "Creation of the Network Assistance Session failed.", "PCF App Session creation failed" , NULL, na_sess->create_event->local.nf_server_interface_metadata, na_sess->create_event->local.app_meta));
@@ -638,7 +639,7 @@ static bool app_session_change_callback(pcf_app_session_t *app_session, void *da
}
- if(na_sess->metadata->delivery_boost){
+ if (na_sess->metadata->delivery_boost) {
delivery_boost_send_response(na_sess);
return false;
}
@@ -648,13 +649,13 @@ static bool app_session_change_callback(pcf_app_session_t *app_session, void *da
return false;
}
- if(app_session && na_sess->metadata->create_event){
+ if (app_session && na_sess->metadata->create_event) {
na_sess->pcf_app_session = app_session;
create_msaf_na_sess_and_send_response(na_sess);
return true;
}
- if(app_session && na_sess->metadata->delivery_boost) {
+ if (app_session && na_sess->metadata->delivery_boost) {
ogs_info("Callback from PCF Update");
activate_delivery_boost_and_send_response(na_sess);
return true;
@@ -683,15 +684,15 @@ static void activate_delivery_boost_and_send_response(msaf_network_assistance_se
response = nf_server_new_response(NULL, "application/json", 0, NULL, cache_control_max_age, NULL, na_sess->metadata->delivery_boost->nf_server_interface_metadata, na_sess->metadata->delivery_boost->app_meta);
ogs_assert(response);
- nf_server_populate_response(response, strlen(success_response), ogs_strdup(success_response), response_code);
+ nf_server_populate_response(response, strlen(success_response), msaf_strdup(success_response), response_code);
ogs_assert(true == ogs_sbi_server_send_response(na_sess->metadata->delivery_boost->h.sbi.data, response));
- if(!na_sess->delivery_boost_timer) na_sess->delivery_boost_timer = ogs_timer_add(ogs_app()->timer_mgr, msaf_timer_delivery_boost, na_sess);
+ if (!na_sess->delivery_boost_timer) na_sess->delivery_boost_timer = ogs_timer_add(ogs_app()->timer_mgr, msaf_timer_delivery_boost, na_sess);
if (na_sess->delivery_boost_timer) {
ogs_timer_start(na_sess->delivery_boost_timer, ogs_time_from_sec(msaf_self()->config.network_assistance_delivery_boost->delivery_boost_period));
}
- if(na_sess->metadata->delivery_boost)
+ if (na_sess->metadata->delivery_boost)
{
msaf_event_free(na_sess->metadata->delivery_boost);
na_sess->metadata->delivery_boost = NULL;
@@ -724,7 +725,7 @@ static void delivery_boost_send_response(msaf_network_assistance_session_t *na_s
response = nf_server_new_response(NULL, "application/json", 0, NULL, 0, NULL, na_sess->metadata->delivery_boost->nf_server_interface_metadata, na_sess->metadata->delivery_boost->app_meta);
ogs_assert(response);
- nf_server_populate_response(response, strlen(success_response), ogs_strdup(success_response), response_code);
+ nf_server_populate_response(response, strlen(success_response), msaf_strdup(success_response), response_code);
ogs_assert(true == ogs_sbi_server_send_response(na_sess->metadata->delivery_boost->h.sbi.data, response));
cJSON_Delete(op_success_response);
@@ -734,7 +735,7 @@ static void delivery_boost_send_response(msaf_network_assistance_session_t *na_s
}
-static bool create_msaf_na_sess_and_send_response(msaf_network_assistance_session_t *na_sess){
+static bool create_msaf_na_sess_and_send_response(msaf_network_assistance_session_t *na_sess) {
ogs_uuid_t uuid;
char id[OGS_UUID_FORMATTED_LENGTH + 1];
ogs_sbi_response_t *response;
@@ -763,7 +764,7 @@ static bool create_msaf_na_sess_and_send_response(msaf_network_assistance_sessio
nf_server_populate_response(response, response_body?strlen(response_body):0, msaf_strdup(response_body), response_code);
ogs_assert(true == ogs_sbi_server_send_response(na_sess->metadata->create_event->h.sbi.data, response));
- if(na_sess->metadata->create_event)
+ if (na_sess->metadata->create_event)
{
msaf_event_free(na_sess->metadata->create_event);
na_sess->metadata->create_event = NULL;
@@ -802,7 +803,7 @@ static bool app_session_notification_callback(pcf_app_session_t *app_session, co
return true;
}
-static bool bsf_retrieve_pcf_binding_callback(OpenAPI_pcf_binding_t *pcf_binding, void *data){
+static bool bsf_retrieve_pcf_binding_callback(OpenAPI_pcf_binding_t *pcf_binding, void *data) {
int rv;
int valid_time = 50;
ogs_time_t expires;
@@ -816,20 +817,20 @@ static bool bsf_retrieve_pcf_binding_callback(OpenAPI_pcf_binding_t *pcf_binding
ogs_assert(ue_address);
- if(pcf_binding){
+ if (pcf_binding) {
const ogs_sockaddr_t *pcf_address;
expires = ogs_time_now() + ogs_time_from_sec(valid_time);
rv = msaf_pcf_cache_add(msaf_self()->pcf_cache, ue_address, (const OpenAPI_pcf_binding_t *)pcf_binding, expires);
OpenAPI_pcf_binding_free(pcf_binding);
- if (rv != true){
+ if (rv != true) {
ogs_error("Adding PCF Binding to the cache failed");
retrieve_pcf_binding_cb_data_free(retrieve_pcf_binding_cb_data);
return false;
}
pcf_address = msaf_pcf_cache_find(msaf_self()->pcf_cache, retrieve_pcf_binding_cb_data->ue_connection->address);
- if(pcf_address){
+ if (pcf_address) {
create_pcf_app_session(pcf_address, retrieve_pcf_binding_cb_data->ue_connection, retrieve_pcf_binding_cb_data->media_component, retrieve_pcf_binding_cb_data->na_sess);
retrieve_pcf_binding_cb_data_free(retrieve_pcf_binding_cb_data);
return true;
@@ -878,12 +879,12 @@ static void retrieve_pcf_binding_cb_data_free(retrieve_pcf_binding_cb_data_t *cb
static void add_create_event_metadata_to_na_sess_context(msaf_network_assistance_session_t *na_sess, msaf_event_t *e)
{
- //if(na_sess->metadata->create_event) msaf_event_free(na_sess->metadata->create_event);
+ //if (na_sess->metadata->create_event) msaf_event_free(na_sess->metadata->create_event);
na_sess->metadata = ogs_calloc(1, sizeof(msaf_network_assistance_session_internal_metadata_t));
na_sess->metadata->create_event = e;
}
-static void add_delivery_boost_event_metadata_to_na_sess_context(msaf_network_assistance_session_t *na_sess, msaf_event_t *e){
+static void add_delivery_boost_event_metadata_to_na_sess_context(msaf_network_assistance_session_t *na_sess, msaf_event_t *e) {
na_sess->metadata->delivery_boost = e;
}
@@ -909,7 +910,7 @@ static char *flow_description_protocol_to_string(int protocol)
static char *flow_description_port(int port)
{
- if (port == 0) return ogs_strdup("");
+ if (port == 0) return msaf_strdup("");
return ogs_msprintf(" %d", port);
}
diff --git a/src/5gmsaf/network-assistance-session.h b/src/5gmsaf/network-assistance-session.h
index daabdce..705f545 100644
--- a/src/5gmsaf/network-assistance-session.h
+++ b/src/5gmsaf/network-assistance-session.h
@@ -1,12 +1,12 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Author: Dev Audsin
+ * 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 MSAF_NETWORK_ASSISTANCE_SESSION_H
#define MSAF_NETWORK_ASSISTANCE_SESSION_H
@@ -31,11 +31,11 @@ typedef struct msaf_event_s msaf_event_t;
typedef struct msaf_network_assistance_session_internal_metadata_s {
msaf_event_t *create_event;
- msaf_event_t *delivery_boost;
+ msaf_event_t *delivery_boost;
} msaf_network_assistance_session_internal_metadata_t;
typedef struct msaf_network_assistance_session_s {
- ogs_lnode_t node;
+ ogs_lnode_t node;
char *naSessionId;
msaf_network_assistance_session_internal_metadata_t *metadata;
msaf_api_network_assistance_session_t *NetworkAssistanceSession;
diff --git a/src/5gmsaf/openapi-extra-yaml/Maf_Management.yaml b/src/5gmsaf/openapi-extra-yaml/Maf_Management.yaml
new file mode 100644
index 0000000..6e24007
--- /dev/null
+++ b/src/5gmsaf/openapi-extra-yaml/Maf_Management.yaml
@@ -0,0 +1,43 @@
+openapi: 3.0.0
+info:
+ title: Maf_Management
+ version: 1.0.0
+ description: |
+ 5GMS AF Maf_Management API
+ Copyright © 2023 British Broadcasting Corporation.
+ All rights reserved.
+tags:
+ - name: Maf_Management
+ description: '5G Media Streaming: AF Management API'
+externalDocs:
+ description: '5G-MAG Reference Tools - 5GMS Application Function'
+ url: 'https://github.com/5G-MAG/rt-common-shared/tree/main/5gms/5G_APIs-overrides'
+servers:
+ - url: '{apiRoot}/5gmag-rt-management/v1'
+ variables:
+ apiRoot:
+ default: https://example.com
+ description: See https://github.com/5G-MAG/rt-5gms-application-function/.
+paths:
+ /provisioning-sessions:
+ get:
+ operationId: enumerateProvisioningSessions
+ summary: 'Retrieve a list of current Provisioning Sessions.'
+ responses:
+ '200':
+ description: 'Success'
+ content:
+ application/json:
+ schema:
+ type: array
+ description: 'A list of current Provisioning Session resource identifiers.'
+ items:
+ $ref: 'TS26512_CommonData.yaml#/components/schemas/ResourceId'
+ '500':
+ # Internal Server Error
+ $ref: 'TS29571_CommonData.yaml#/components/responses/500'
+ '503':
+ # Service Unavailable
+ $ref: 'TS29571_CommonData.yaml#/components/responses/503'
+ default:
+ $ref: 'TS29571_CommonData.yaml#/components/responses/default'
diff --git a/src/5gmsaf/pcf-cache.c b/src/5gmsaf/pcf-cache.c
index 5d259e4..2880a13 100644
--- a/src/5gmsaf/pcf-cache.c
+++ b/src/5gmsaf/pcf-cache.c
@@ -1,12 +1,12 @@
/*
-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
-*/
+ * 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 "ogs-sbi.h"
@@ -68,7 +68,7 @@ bool msaf_pcf_cache_add(msaf_pcf_cache_t *cache, const ogs_sockaddr_t *ue_addres
const ogs_sockaddr_t *msaf_pcf_cache_find(msaf_pcf_cache_t *cache, const ogs_sockaddr_t *ue_address)
{
msaf_pcf_cache_entry_t *entry;
-
+
entry = ogs_hash_get(cache, ue_address, sizeof(*ue_address));
if (!entry) return NULL;
diff --git a/src/5gmsaf/pcf-cache.h b/src/5gmsaf/pcf-cache.h
index 948409f..8ee5a18 100644
--- a/src/5gmsaf/pcf-cache.h
+++ b/src/5gmsaf/pcf-cache.h
@@ -1,12 +1,12 @@
/*
-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
-*/
+ * 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 MSAF_PCF_CACHE_H
#define MSAF_PCF_CACHE_H
diff --git a/src/5gmsaf/pcf-session.c b/src/5gmsaf/pcf-session.c
index ab517df..eb84720 100644
--- a/src/5gmsaf/pcf-session.c
+++ b/src/5gmsaf/pcf-session.c
@@ -1,12 +1,13 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Authors: Dev Audsin
+ * David Waring
+ * Copyright: (C) 2023-2024 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 "pcf-session.h"
@@ -15,7 +16,7 @@ static void msaf_pcf_session_remove(msaf_pcf_session_t *pcf_sess);
pcf_session_t *msaf_pcf_session_new(const ogs_sockaddr_t *pcf_address)
{
- msaf_pcf_session_t *msaf_pcf_session;
+ msaf_pcf_session_t *msaf_pcf_session;
msaf_pcf_session = ogs_calloc(1, sizeof(msaf_pcf_session_t));
msaf_pcf_session->pcf_session = pcf_session_new(pcf_address);
ogs_list_add(&msaf_self()->pcf_sessions, msaf_pcf_session);
@@ -26,8 +27,8 @@ void msaf_pcf_session_remove_all()
{
msaf_pcf_session_t *msaf_pcf_session = NULL, *next = NULL;
- ogs_list_for_each_safe(&msaf_self()->pcf_sessions, next, msaf_pcf_session){
- ogs_list_remove(&msaf_self()->pcf_sessions, msaf_pcf_session);
+ ogs_list_for_each_safe(&msaf_self()->pcf_sessions, next, msaf_pcf_session) {
+ ogs_list_remove(&msaf_self()->pcf_sessions, msaf_pcf_session);
msaf_pcf_session_remove(msaf_pcf_session);
}
}
diff --git a/src/5gmsaf/pcf-session.h b/src/5gmsaf/pcf-session.h
index c2ca4c5..1f7a60a 100644
--- a/src/5gmsaf/pcf-session.h
+++ b/src/5gmsaf/pcf-session.h
@@ -1,12 +1,12 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Author: Dev Audsin
+ * 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 MSAF_PCF_SESSION_H
#define MSAF_PCF_SESSION_H
@@ -19,7 +19,7 @@ extern "C" {
#endif
typedef struct msaf_pcf_session_s {
- ogs_lnode_t node;
+ ogs_lnode_t node;
pcf_session_t *pcf_session;
} msaf_pcf_session_t;
diff --git a/src/5gmsaf/policy-template.c b/src/5gmsaf/policy-template.c
index 81dea2e..d10003d 100644
--- a/src/5gmsaf/policy-template.c
+++ b/src/5gmsaf/policy-template.c
@@ -1,11 +1,13 @@
/*
-License: 5G-MAG Public License (v1.0)
-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Authors: Dev Audsin
+ * David Waring
+ * Copyright: (C) 2023-2024 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 "policy-template.h"
@@ -25,8 +27,8 @@ msaf_api_policy_template_t *msaf_policy_template_parseFromJSON(cJSON *policy_tem
void msaf_policy_template_set_id(msaf_api_policy_template_t *policy_template, const char *policy_template_id)
{
ogs_assert(policy_template);
- if(policy_template->policy_template_id) ogs_free(policy_template->policy_template_id);
- policy_template->policy_template_id = policy_template_id?ogs_strdup(policy_template_id):NULL;
+ if (policy_template->policy_template_id) ogs_free(policy_template->policy_template_id);
+ policy_template->policy_template_id = msaf_strdup(policy_template_id);
}
char *calculate_policy_template_hash(msaf_api_policy_template_t *policy_template)
@@ -63,49 +65,49 @@ bool msaf_policy_template_set_state(msaf_api_policy_template_t *policy_template,
ogs_assert(policy_template);
ogs_assert(provisioning_session);
- if(policy_template->state == msaf_api_policy_template_STATE_NULL) {
- if(new_state == msaf_api_policy_template_STATE_NULL) return false;
+ if (policy_template->state == msaf_api_policy_template_STATE_NULL) {
+ if (new_state == msaf_api_policy_template_STATE_NULL) return false;
- if(new_state == msaf_api_policy_template_STATE_PENDING) {
- policy_template->state = msaf_api_policy_template_STATE_PENDING;
+ if (new_state == msaf_api_policy_template_STATE_VAL_PENDING) {
+ policy_template->state = msaf_api_policy_template_STATE_VAL_PENDING;
msaf_policy_template_set_state_reason(policy_template, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
return true;
}
- if(new_state == msaf_api_policy_template_STATE_READY || new_state == msaf_api_policy_template_STATE_INVALID || new_state == msaf_api_policy_template_STATE_SUSPENDED) {
- ogs_error("Invalid state change");
+ if (new_state == msaf_api_policy_template_STATE_VAL_READY || new_state == msaf_api_policy_template_STATE_VAL_INVALID || new_state == msaf_api_policy_template_STATE_VAL_SUSPENDED) {
+ ogs_error("Invalid state change");
return false;
- }
+ }
}
- if(policy_template->state == msaf_api_policy_template_STATE_PENDING) {
+ if (policy_template->state == msaf_api_policy_template_STATE_VAL_PENDING) {
- if(new_state == msaf_api_policy_template_STATE_NULL) {
+ if (new_state == msaf_api_policy_template_STATE_NULL) {
policy_template->state = msaf_api_policy_template_STATE_NULL;
- msaf_policy_template_set_state_reason(policy_template, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
- return true;
+ msaf_policy_template_set_state_reason(policy_template, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ return true;
}
- if(new_state == msaf_api_policy_template_STATE_PENDING) return false;
+ if (new_state == msaf_api_policy_template_STATE_VAL_PENDING) return false;
- if(new_state == msaf_api_policy_template_STATE_READY) {
- if(provisioning_session->sai_cache)
+ if (new_state == msaf_api_policy_template_STATE_VAL_READY) {
+ if (provisioning_session->sai_cache)
msaf_sai_cache_clear(provisioning_session->sai_cache);
- policy_template->state = msaf_api_policy_template_STATE_READY;
+ policy_template->state = msaf_api_policy_template_STATE_VAL_READY;
msaf_policy_template_set_state_reason(policy_template, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
- return true;
+ return true;
}
-
- if(new_state == msaf_api_policy_template_STATE_INVALID) {
- char *detail = "Policy template state transitioned from PENDING to INVALID.";
- char *title = "Provider decision.";
- policy_template->state = msaf_api_policy_template_STATE_INVALID;
- msaf_policy_template_set_state_reason(policy_template, NULL, msaf_strdup(detail), NULL, NULL, NULL, msaf_strdup(title), NULL);
+
+ if (new_state == msaf_api_policy_template_STATE_VAL_INVALID) {
+ char *detail = "Policy template state transitioned from PENDING to INVALID.";
+ char *title = "Provider decision.";
+ policy_template->state = msaf_api_policy_template_STATE_VAL_INVALID;
+ msaf_policy_template_set_state_reason(policy_template, NULL, msaf_strdup(detail), NULL, NULL, NULL, msaf_strdup(title), NULL);
return true;
}
-
- if(new_state == msaf_api_policy_template_STATE_SUSPENDED) {
+
+ if (new_state == msaf_api_policy_template_STATE_VAL_SUSPENDED) {
ogs_error("Invalid state change");
return false;
}
@@ -113,84 +115,84 @@ bool msaf_policy_template_set_state(msaf_api_policy_template_t *policy_template,
}
- if(policy_template->state == msaf_api_policy_template_STATE_READY) {
+ if (policy_template->state == msaf_api_policy_template_STATE_VAL_READY) {
- if(new_state == msaf_api_policy_template_STATE_NULL) {
- if (provisioning_session->sai_cache)
+ if (new_state == msaf_api_policy_template_STATE_NULL) {
+ if (provisioning_session->sai_cache)
msaf_sai_cache_clear(provisioning_session->sai_cache);
policy_template->state = msaf_api_policy_template_STATE_NULL;
msaf_policy_template_set_state_reason(policy_template, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
return true;
- }
+ }
- if(new_state == msaf_api_policy_template_STATE_PENDING) {
- if(provisioning_session->sai_cache)
+ if (new_state == msaf_api_policy_template_STATE_VAL_PENDING) {
+ if (provisioning_session->sai_cache)
msaf_sai_cache_clear(provisioning_session->sai_cache);
- policy_template->state = msaf_api_policy_template_STATE_PENDING;
+ policy_template->state = msaf_api_policy_template_STATE_VAL_PENDING;
msaf_policy_template_set_state_reason(policy_template, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
return true;
}
-
- if(new_state == msaf_api_policy_template_STATE_READY) return false;
-
- if(new_state == msaf_api_policy_template_STATE_INVALID) {
+
+ if (new_state == msaf_api_policy_template_STATE_VAL_READY) return false;
+
+ if (new_state == msaf_api_policy_template_STATE_VAL_INVALID) {
ogs_error("Invalid state change");
return false;
}
-
- if(new_state == msaf_api_policy_template_STATE_SUSPENDED) {
- char *detail = "Policy template state transitioned from READY to SUSPENDED.";
- char *title = "Operator Decision.";
- if (provisioning_session->sai_cache)
- msaf_sai_cache_clear(provisioning_session->sai_cache);
- policy_template->state = msaf_api_policy_template_STATE_SUSPENDED;
- msaf_policy_template_set_state_reason(policy_template, NULL, msaf_strdup(detail), NULL, NULL, NULL, msaf_strdup(title), NULL);
+
+ if (new_state == msaf_api_policy_template_STATE_VAL_SUSPENDED) {
+ char *detail = "Policy template state transitioned from READY to SUSPENDED.";
+ char *title = "Operator Decision.";
+ if (provisioning_session->sai_cache)
+ msaf_sai_cache_clear(provisioning_session->sai_cache);
+ policy_template->state = msaf_api_policy_template_STATE_VAL_SUSPENDED;
+ msaf_policy_template_set_state_reason(policy_template, NULL, msaf_strdup(detail), NULL, NULL, NULL, msaf_strdup(title), NULL);
return true;
}
}
- if(policy_template->state == msaf_api_policy_template_STATE_INVALID) {
-
- if(new_state == msaf_api_policy_template_STATE_NULL) {
+ if (policy_template->state == msaf_api_policy_template_STATE_VAL_INVALID) {
+
+ if (new_state == msaf_api_policy_template_STATE_NULL) {
policy_template->state = msaf_api_policy_template_STATE_NULL;
msaf_policy_template_set_state_reason(policy_template, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
- return true;
+ return true;
}
- if(new_state == msaf_api_policy_template_STATE_PENDING) {
- policy_template->state = msaf_api_policy_template_STATE_PENDING;
+ if (new_state == msaf_api_policy_template_STATE_VAL_PENDING) {
+ policy_template->state = msaf_api_policy_template_STATE_VAL_PENDING;
msaf_policy_template_set_state_reason(policy_template, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
- return true;
+ return true;
}
- if(new_state == msaf_api_policy_template_STATE_READY || new_state == msaf_api_policy_template_STATE_SUSPENDED) {
+ if (new_state == msaf_api_policy_template_STATE_VAL_READY || new_state == msaf_api_policy_template_STATE_VAL_SUSPENDED) {
ogs_error("Invalid state change");
return false;
}
- if(new_state == msaf_api_policy_template_STATE_INVALID) return false;
+ if (new_state == msaf_api_policy_template_STATE_VAL_INVALID) return false;
}
- if(policy_template->state == msaf_api_policy_template_STATE_SUSPENDED) {
-
- if(new_state == msaf_api_policy_template_STATE_NULL) {
+ if (policy_template->state == msaf_api_policy_template_STATE_VAL_SUSPENDED) {
+
+ if (new_state == msaf_api_policy_template_STATE_NULL) {
policy_template->state = msaf_api_policy_template_STATE_NULL;
msaf_policy_template_set_state_reason(policy_template, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
- return true;
+ return true;
}
- if(new_state == msaf_api_policy_template_STATE_PENDING) {
- policy_template->state = msaf_api_policy_template_STATE_PENDING;
+ if (new_state == msaf_api_policy_template_STATE_VAL_PENDING) {
+ policy_template->state = msaf_api_policy_template_STATE_VAL_PENDING;
msaf_policy_template_set_state_reason(policy_template, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
- return true;
+ return true;
}
- if(new_state == msaf_api_policy_template_STATE_READY || (new_state == msaf_api_policy_template_STATE_INVALID)) {
+ if (new_state == msaf_api_policy_template_STATE_VAL_READY || (new_state == msaf_api_policy_template_STATE_VAL_INVALID)) {
ogs_error("Invalid state change");
return false;
}
- if(new_state == msaf_api_policy_template_STATE_SUSPENDED) return false;
+ if (new_state == msaf_api_policy_template_STATE_VAL_SUSPENDED) return false;
}
return false;
@@ -217,7 +219,7 @@ OpenAPI_list_t *get_id_of_policy_templates_in_ready_state(ogs_hash_t *policy_tem
for (hi = ogs_hash_first(policy_templates);
hi; hi = ogs_hash_next(hi)) {
policy_template_node = (msaf_policy_template_node_t *)ogs_hash_this_val(hi);
- if (policy_template_node->policy_template->state == msaf_api_policy_template_STATE_READY) {
+ if (policy_template_node->policy_template->state == msaf_api_policy_template_STATE_VAL_READY) {
OpenAPI_list_add(valid_policy_template_ids, msaf_strdup(policy_template_node->policy_template->policy_template_id));
}
}
@@ -235,7 +237,7 @@ OpenAPI_list_t *get_external_reference_of_policy_templates_in_ready_state(ogs_ha
for (hi = ogs_hash_first(policy_templates);
hi; hi = ogs_hash_next(hi)) {
policy_template_node = (msaf_policy_template_node_t *)ogs_hash_this_val(hi);
- if (policy_template_node->policy_template->state == msaf_api_policy_template_STATE_READY) {
+ if (policy_template_node->policy_template->state == msaf_api_policy_template_STATE_VAL_READY) {
OpenAPI_list_add(external_references, msaf_strdup(policy_template_node->policy_template->external_reference));
}
}
@@ -275,7 +277,7 @@ void msaf_policy_template_node_free(msaf_policy_template_node_t *node)
static void msaf_policy_template_set_state_reason(msaf_api_policy_template_t *policy_template, char *cause, char *detail, char *instance, char *nrf_id, char *supported_features, char *title, char *type)
{
- if(policy_template->state_reason) msaf_api_problem_details_free(policy_template->state_reason);
+ if (policy_template->state_reason) msaf_api_problem_details_free(policy_template->state_reason);
policy_template->state_reason = msaf_api_problem_details_create(NULL, NULL, cause, detail, instance, NULL, nrf_id, 0, 0, supported_features, title, type);
}
diff --git a/src/5gmsaf/policy-template.h b/src/5gmsaf/policy-template.h
index bb9c244..df9ebf0 100644
--- a/src/5gmsaf/policy-template.h
+++ b/src/5gmsaf/policy-template.h
@@ -1,12 +1,12 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Author: Dev Audsin
+ * 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 MSAF_POLICY_TEMPLATE_H
#define MSAF_POLICY_TEMPLATE_H
@@ -44,7 +44,7 @@ extern bool msaf_policy_template_clear(ogs_hash_t *policy_templates);
extern void msaf_policy_template_node_free(msaf_policy_template_node_t *node);
cJSON *msaf_policy_template_convert_to_json(msaf_api_policy_template_t *policy_template);
-
+
#ifdef __cplusplus
}
#endif
diff --git a/src/5gmsaf/provisioning-session.c b/src/5gmsaf/provisioning-session.c
index e122298..816ebed 100644
--- a/src/5gmsaf/provisioning-session.c
+++ b/src/5gmsaf/provisioning-session.c
@@ -1,12 +1,13 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-Copyright: (C) 2022-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Authors: Dev Audsin
+ * David Waring
+ * Copyright: (C) 2022-2024 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
#include "application-server-context.h"
@@ -15,6 +16,7 @@ program. If this file is missing then the license can be retrieved from
#include "context.h"
#include "utilities.h"
#include "hash.h"
+#include "metrics-reporting-configuration.h"
#include "sai-cache.h"
#include "openapi/model/msaf_api_consumption_reporting_configuration.h"
@@ -115,6 +117,7 @@ msaf_provisioning_session_create(const char *provisioning_session_type, const ch
msaf_provisioning_session->httpMetadata.provisioningSession.received = time(NULL);
msaf_provisioning_session->httpMetadata.provisioningSession.hash = calculate_provisioning_session_hash(provisioning_session);
+ msaf_provisioning_session->metrics_reporting_map = msaf_metrics_reporting_map();
msaf_provisioning_session->certificate_map = msaf_certificate_map();
msaf_provisioning_session->policy_templates = msaf_policy_templates_new();
ogs_hash_set(msaf_self()->provisioningSessions_map, msaf_strdup(msaf_provisioning_session->provisioningSessionId), OGS_HASH_KEY_STRING, msaf_provisioning_session);
@@ -150,10 +153,10 @@ void msaf_provisioning_session_free(msaf_provisioning_session_t *provisioning_se
safe_ogs_free(provisioning_session->httpMetadata.contentHostingConfiguration.hash);
msaf_consumption_report_configuration_deregister(provisioning_session);
- if(provisioning_session->sai_cache)
+ if (provisioning_session->sai_cache)
msaf_sai_cache_free(provisioning_session->sai_cache);
- if(provisioning_session->policy_templates)
+ if (provisioning_session->policy_templates)
msaf_provisioning_session_policy_template_free(provisioning_session->policy_templates);
ogs_list_for_each_safe(&provisioning_session->application_server_states, next_as_state_ref, as_state_ref) {
@@ -161,6 +164,16 @@ void msaf_provisioning_session_free(msaf_provisioning_session_t *provisioning_se
ogs_free(as_state_ref);
}
+ if (provisioning_session->metrics_reporting_map) {
+ free_ogs_hash_context_t fohc = {
+ (void(*)(void*))msaf_metrics_reporting_configuration_free,
+ provisioning_session->metrics_reporting_map
+ };
+ ogs_hash_do(free_ogs_hash_entry, &fohc, provisioning_session->metrics_reporting_map);
+ ogs_hash_destroy(provisioning_session->metrics_reporting_map);
+ provisioning_session->metrics_reporting_map = NULL;
+ }
+
ogs_free(provisioning_session);
}
@@ -175,7 +188,6 @@ msaf_provisioning_session_get_json(const char *provisioning_session_id)
if (msaf_provisioning_session) {
msaf_api_provisioning_session_t *provisioning_session;
- ogs_hash_index_t *cert_node;
provisioning_session = ogs_calloc(1,sizeof(*provisioning_session));
ogs_assert(provisioning_session);
@@ -185,10 +197,21 @@ msaf_provisioning_session_get_json(const char *provisioning_session_id)
provisioning_session->asp_id = msaf_provisioning_session->aspId;
provisioning_session->app_id = msaf_provisioning_session->appId;
- 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", (const char *)ogs_hash_this_key(cert_node));
- OpenAPI_list_add(provisioning_session->server_certificate_ids, (void*)ogs_hash_this_key(cert_node));
+ if (msaf_provisioning_session->certificate_map && ogs_hash_first(msaf_provisioning_session->certificate_map) != NULL) {
+ ogs_hash_index_t *cert_node;
+ 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", (const char *)ogs_hash_this_key(cert_node));
+ OpenAPI_list_add(provisioning_session->server_certificate_ids, (void*)ogs_hash_this_key(cert_node));
+ }
+ }
+
+ if (msaf_provisioning_session->metrics_reporting_map && ogs_hash_first(msaf_provisioning_session->metrics_reporting_map) != NULL) {
+ ogs_hash_index_t *metrics_node;
+ provisioning_session->metrics_reporting_configuration_ids = (OpenAPI_set_t*)OpenAPI_list_create();
+ for (metrics_node=ogs_hash_first(msaf_provisioning_session->metrics_reporting_map); metrics_node; metrics_node = ogs_hash_next(metrics_node)) {
+ OpenAPI_list_add(provisioning_session->metrics_reporting_configuration_ids, (void*)ogs_hash_this_key(metrics_node));
+ }
}
if (msaf_provisioning_session->policy_templates && ogs_hash_first(msaf_provisioning_session->policy_templates) != NULL) {
@@ -204,6 +227,7 @@ msaf_provisioning_session_get_json(const char *provisioning_session_id)
OpenAPI_list_free(provisioning_session->server_certificate_ids);
OpenAPI_list_free(provisioning_session->policy_template_ids);
+ OpenAPI_list_free(provisioning_session->metrics_reporting_configuration_ids);
ogs_free(provisioning_session);
} else {
ogs_error("Unable to retrieve Provisioning Session [%s]", provisioning_session_id);
@@ -255,14 +279,14 @@ msaf_delete_certificates(const char *provisioning_session_id)
if (as_state->current_certificates) {
resource_id_node_t *certificate, *next;
- ogs_list_for_each_safe(as_state->current_certificates, next, certificate){
+ ogs_list_for_each_safe(as_state->current_certificates, next, certificate) {
char *cert_id;
char *provisioning_session;
char *current_cert_id = msaf_strdup(certificate->state);
provisioning_session = strtok_r(current_cert_id,":",&cert_id);
- if(!strcmp(provisioning_session, provisioning_session_id)) {
+ 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));
@@ -271,7 +295,7 @@ msaf_delete_certificates(const char *provisioning_session_id)
ogs_list_add(&as_state->delete_certificates, delete_cert);
}
- if(current_cert_id)
+ if (current_cert_id)
ogs_free(current_cert_id);
}
}
@@ -307,7 +331,7 @@ msaf_delete_content_hosting_configuration(const char *provisioning_session_id)
if (as_state->current_content_hosting_configurations) {
- ogs_list_for_each_safe(as_state->current_content_hosting_configurations, next, content_hosting_configuration){
+ ogs_list_for_each_safe(as_state->current_content_hosting_configurations, next, content_hosting_configuration) {
if (!strcmp(content_hosting_configuration->state, provisioning_session_id))
break;
@@ -321,7 +345,7 @@ msaf_delete_content_hosting_configuration(const char *provisioning_session_id)
}
}
- ogs_list_for_each_safe(&as_state->upload_content_hosting_configurations, next_node, upload_content_hosting_configuration){
+ ogs_list_for_each_safe(&as_state->upload_content_hosting_configurations, next_node, upload_content_hosting_configuration) {
if (!strcmp(upload_content_hosting_configuration->state, provisioning_session_id))
break;
}
@@ -348,7 +372,7 @@ msaf_provisioning_session_find_by_provisioningSessionId(const char *provisioning
msaf_policy_template_node_t *
msaf_provisioning_session_find_policy_template_by_id(msaf_provisioning_session_t *provisioning_session, const char *policy_template_id)
{
- if(!provisioning_session->policy_templates) return NULL;
+ if (!provisioning_session->policy_templates) return NULL;
return (msaf_policy_template_node_t *) ogs_hash_get(provisioning_session->policy_templates, policy_template_id, OGS_HASH_KEY_STRING);
}
@@ -356,7 +380,7 @@ msaf_policy_template_node_t *msaf_provisioning_session_get_policy_template_by_id
msaf_provisioning_session_t *provisioning_session;
provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(provisioning_session_id);
- if(!provisioning_session) return NULL;
+ if (!provisioning_session) return NULL;
return msaf_provisioning_session_find_policy_template_by_id(provisioning_session, policy_template_id);
}
@@ -392,7 +416,7 @@ msaf_retrieve_certificates_from_map(msaf_provisioning_session_t *provisioning_se
dist_config = (msaf_api_distribution_configuration_t*)dist_config_node->data;
if (dist_config->certificate_id) {
const char *cert = ogs_hash_get(provisioning_session->certificate_map, dist_config->certificate_id, OGS_HASH_KEY_STRING);
- if (cert){
+ if (cert) {
certificate = ogs_calloc(1, sizeof(resource_id_node_t));
ogs_assert(certificate);
char *provisioning_session_id_plus_cert_id = ogs_msprintf("%s:%s", provisioning_session->provisioningSessionId, dist_config->certificate_id);
@@ -451,7 +475,7 @@ msaf_distribution_create(cJSON *content_hosting_config, msaf_provisioning_sessio
dist_config = (msaf_api_distribution_configuration_t*)dist_config_node->data;
- if(dist_config->entry_point && !uri_relative_check(dist_config->entry_point->relative_path)) {
+ if (dist_config->entry_point && !uri_relative_check(dist_config->entry_point->relative_path)) {
if (reason_ret) *reason_ret = "distributionConfiguration.entryPoint.relativePath malformed";
ogs_error("distributionConfiguration.entryPoint.relativePath malformed for Provisioning Session [%s]", provisioning_session->provisioningSessionId);
cJSON_Delete(content_hosting_config);
@@ -477,16 +501,16 @@ msaf_distribution_create(cJSON *content_hosting_config, msaf_provisioning_sessio
protocol = "https";
}
- if(dist_config->domain_name_alias){
+ 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);
+ 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);
- }
+ }
} else {
ogs_error("The Content Hosting Configuration has no distributionConfigurations for Provisioning Session [%s]", provisioning_session->provisioningSessionId);
}
@@ -519,7 +543,7 @@ cJSON *msaf_get_content_hosting_configuration_by_provisioning_session_id(const c
msaf_provisioning_session = msaf_provisioning_session_find_by_provisioningSessionId(provisioning_session_id);
- if(msaf_provisioning_session && msaf_provisioning_session->contentHostingConfiguration)
+ if (msaf_provisioning_session && msaf_provisioning_session->contentHostingConfiguration)
{
content_hosting_configuration_json = msaf_api_content_hosting_configuration_convertResponseToJSON(msaf_provisioning_session->contentHostingConfiguration);
} else {
@@ -623,7 +647,7 @@ char *enumerate_provisioning_sessions(void)
}
bool msaf_provisioning_session_add_policy_template(msaf_provisioning_session_t *provisioning_session, msaf_api_policy_template_t *policy_template, time_t creation_time) {
-
+
ogs_uuid_t uuid;
char id[OGS_UUID_FORMATTED_LENGTH + 1];
msaf_policy_template_node_t *msaf_policy_template;
@@ -632,13 +656,13 @@ bool msaf_provisioning_session_add_policy_template(msaf_provisioning_session_t *
ogs_uuid_format(id, &uuid);
msaf_policy_template_set_id(policy_template, id);
-
+
msaf_policy_template = msaf_policy_template_populate(policy_template, creation_time);
- if(!msaf_policy_template) return false;
+ if (!msaf_policy_template) return false;
ogs_hash_set(provisioning_session->policy_templates, msaf_strdup(id), OGS_HASH_KEY_STRING, msaf_policy_template);
- if(!msaf_provisioning_session_send_policy_template_state_change_event(provisioning_session, msaf_policy_template, msaf_api_policy_template_STATE_PENDING, NULL, NULL))
+ if (!msaf_provisioning_session_send_policy_template_state_change_event(provisioning_session, msaf_policy_template, msaf_api_policy_template_STATE_VAL_PENDING, NULL, NULL))
return false;
return true;
@@ -646,8 +670,8 @@ bool msaf_provisioning_session_add_policy_template(msaf_provisioning_session_t *
}
bool msaf_provisioning_session_update_policy_template(msaf_provisioning_session_t *provisioning_session, msaf_policy_template_node_t *msaf_policy_template, msaf_api_policy_template_t *policy_template) {
-
- char *policy_template_id;
+
+ char *policy_template_id;
ogs_assert(provisioning_session);
ogs_assert(msaf_policy_template);
ogs_assert(policy_template);
@@ -657,7 +681,7 @@ bool msaf_provisioning_session_update_policy_template(msaf_provisioning_session_
msaf_policy_template_free(msaf_policy_template->policy_template);
msaf_policy_template->policy_template = policy_template;
msaf_policy_template->policy_template->policy_template_id = policy_template_id;
- if(!msaf_provisioning_session_send_policy_template_state_change_event(provisioning_session, msaf_policy_template, msaf_api_policy_template_STATE_PENDING, NULL, NULL))
+ if (!msaf_provisioning_session_send_policy_template_state_change_event(provisioning_session, msaf_policy_template, msaf_api_policy_template_STATE_VAL_PENDING, NULL, NULL))
return false;
return true;
@@ -666,7 +690,7 @@ bool msaf_provisioning_session_update_policy_template(msaf_provisioning_session_
bool msaf_provisioning_session_send_policy_template_state_change_event(msaf_provisioning_session_t *provisioning_session, msaf_policy_template_node_t *policy_template, msaf_api_policy_template_state_e new_state, msaf_policy_template_state_change_callback callback, void *user_data)
{
msaf_event_t *event;
- int rv;
+ int rv;
ogs_assert(provisioning_session);
ogs_assert(policy_template);
@@ -687,9 +711,9 @@ bool msaf_provisioning_session_send_policy_template_state_change_event(msaf_prov
bool msaf_provisioning_session_delete_policy_template(msaf_provisioning_session_t *provisioning_session, msaf_policy_template_node_t *policy_template)
{
- if(!policy_template || !policy_template->policy_template) return false;
+ if (!policy_template || !policy_template->policy_template) return false;
- if(!msaf_provisioning_session_delete_policy_template_by_id(provisioning_session, policy_template->policy_template->policy_template_id))
+ if (!msaf_provisioning_session_delete_policy_template_by_id(provisioning_session, policy_template->policy_template->policy_template_id))
return false;
return true;
}
@@ -753,8 +777,8 @@ static msaf_policy_template_change_state_event_data_t *msaf_policy_template_chan
msaf_policy_template_change_state_event_data->new_state = new_state;
msaf_policy_template_change_state_event_data->callback = callback;
msaf_policy_template_change_state_event_data->callback_user_data = user_data;
-
- return msaf_policy_template_change_state_event_data;
+
+ return msaf_policy_template_change_state_event_data;
}
@@ -763,9 +787,9 @@ static void msaf_provisioning_session_policy_template_delete(msaf_provisioning_s
ogs_assert(msaf_provisioning_session);
ogs_assert(policy_template_node);
ogs_assert(user_data);
-
+
ogs_hash_do(free_ogs_hash_provisioning_session_policy_template, user_data, msaf_provisioning_session->policy_templates);
-}
+}
static int
free_ogs_hash_provisioning_session_policy_template(void *rec, const void *key, int klen, const void *value)
@@ -898,8 +922,8 @@ static int
free_ogs_hash_entry(void *rec, const void *key, int klen, const void *value)
{
free_ogs_hash_context_t *fohc = (free_ogs_hash_context_t*)rec;
- fohc->value_free_fn((void*)value);
ogs_hash_set(fohc->hash, key, klen, NULL);
+ fohc->value_free_fn((void*)value);
ogs_free((void*)key);
return 1;
}
diff --git a/src/5gmsaf/provisioning-session.h b/src/5gmsaf/provisioning-session.h
index 64d88ea..880abff 100644
--- a/src/5gmsaf/provisioning-session.h
+++ b/src/5gmsaf/provisioning-session.h
@@ -1,12 +1,12 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-Copyright: (C) 2022-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Author: Dev Audsin
+ * Copyright: (C) 2022-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 MSAF_PROVISIONING_SESSION_H
#define MSAF_PROVISIONING_SESSION_H
@@ -17,6 +17,7 @@ program. If this file is missing then the license can be retrieved from
#include "openapi/model/msaf_api_provisioning_session_type.h"
#include "openapi/model/msaf_api_policy_template.h"
+#include "openapi/model/msaf_api_metrics_reporting_configuration.h"
#ifdef __cplusplus
extern "C" {
@@ -51,6 +52,7 @@ typedef struct msaf_provisioning_session_s {
} httpMetadata;
ogs_hash_t *certificate_map; //Type: char* => n/a (just used as a set - external tool manages data)
ogs_hash_t *policy_templates; /* key: policy template id, value: msaf_policy_template_node_t */
+ ogs_hash_t *metrics_reporting_map;
ogs_list_t application_server_states; //Type: msaf_application_server_state_ref_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
index 44a92db..d47147f 100644
--- a/src/5gmsaf/response-cache-control.c
+++ b/src/5gmsaf/response-cache-control.c
@@ -1,12 +1,12 @@
/*
-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
+ */
#include "context.h"
#include "response-cache-control.h"
@@ -20,6 +20,7 @@ void msaf_server_response_cache_control_set(void)
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->m1_metrics_reporting_response_max_age = SERVER_RESPONSE_MAX_AGE;
server_response_cache_control->m1_consumption_reporting_response_max_age = SERVER_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;
@@ -27,13 +28,14 @@ void msaf_server_response_cache_control_set(void)
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 m1_consumption_reporting_response_max_age,
+ int m1_content_protocols_response_max_age, int m1_metrics_reporting_response_max_age, int m1_consumption_reporting_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->m1_metrics_reporting_response_max_age = m1_metrics_reporting_response_max_age;
msaf_self()->config.server_response_cache_control->m1_consumption_reporting_response_max_age = m1_consumption_reporting_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 d7ad282..80ee2a4 100644
--- a/src/5gmsaf/response-cache-control.h
+++ b/src/5gmsaf/response-cache-control.h
@@ -1,12 +1,12 @@
/*
-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_RESPONSE_CACHE_CONTROL_H
#define MSAF_RESPONSE_CACHE_CONTROL_H
@@ -25,12 +25,13 @@ typedef struct msaf_server_response_cache_control_s {
int m1_content_hosting_configurations_response_max_age;
int m1_server_certificates_response_max_age;
int m1_content_protocols_response_max_age;
+ int m1_metrics_reporting_response_max_age;
int m1_consumption_reporting_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_server_certificates_response_max_age, int m1_content_protocols_response_max_age, int m1_consumption_reporting_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 m1_metrics_reporting_response_max_age, int m1_consumption_reporting_response_max_age, int m5_service_access_information_response_max_age);
#ifdef __cplusplus
diff --git a/src/5gmsaf/sai-cache.c b/src/5gmsaf/sai-cache.c
index 54eedc7..0998749 100644
--- a/src/5gmsaf/sai-cache.c
+++ b/src/5gmsaf/sai-cache.c
@@ -1,12 +1,12 @@
/*
-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
-*/
+ * 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 _GNU_SOURCE
#define _GNU_SOURCE
diff --git a/src/5gmsaf/sai-cache.h b/src/5gmsaf/sai-cache.h
index 63d043f..545d3ae 100644
--- a/src/5gmsaf/sai-cache.h
+++ b/src/5gmsaf/sai-cache.h
@@ -1,12 +1,12 @@
/*
-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
-*/
+ * 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 MSAF_SAI_CACHE_H
#define MSAF_SAI_CACHE_H
diff --git a/src/5gmsaf/sbi-path.c b/src/5gmsaf/sbi-path.c
index 1f05e3f..ed2816f 100644
--- a/src/5gmsaf/sbi-path.c
+++ b/src/5gmsaf/sbi-path.c
@@ -1,12 +1,12 @@
/*
-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
+ */
#include "ogs-sbi.h"
#include "sbi-path.h"
@@ -53,10 +53,10 @@ int msaf_sbi_open(void)
ogs_sbi_nf_fsm_init(nf_instance);
}
- /*
+ /*
ogs_sbi_subscription_spec_add(
OpenAPI_nf_type_BSF, OGS_SBI_SERVICE_NAME_NBSF_MANAGEMENT);
- */
+ */
if (ogs_sbi_server_start_all(server_cb) != OGS_OK)
return OGS_ERROR;
diff --git a/src/5gmsaf/sbi-path.h b/src/5gmsaf/sbi-path.h
index f023c92..c901564 100644
--- a/src/5gmsaf/sbi-path.h
+++ b/src/5gmsaf/sbi-path.h
@@ -1,11 +1,11 @@
/*
-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_SBI_PATH_H
diff --git a/src/5gmsaf/server.c b/src/5gmsaf/server.c
index c62ccb9..4baf5cd 100644
--- a/src/5gmsaf/server.c
+++ b/src/5gmsaf/server.c
@@ -1,12 +1,13 @@
/*
-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)
+ * Authors: Dev Audsin
+ * David Waring
+ * Copyright: (C) 2022-2024 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"
@@ -23,8 +24,8 @@ static bool nf_build_content(ogs_sbi_http_message_t *http, ogs_sbi_message_t *me
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 *allow_methods, const nf_server_interface_metadata_t *interface,
+ogs_sbi_response_t *nf_server_new_response(const char *location, const char *content_type, time_t last_modified, const char *etag,
+ int cache_control, const char *allow_methods, const nf_server_interface_metadata_t *interface,
const nf_server_app_metadata_t *app)
{
ogs_sbi_response_t *response = NULL;
@@ -34,29 +35,29 @@ ogs_sbi_response_t *nf_server_new_response(char *location, char *content_type, t
response = ogs_sbi_response_new();
ogs_expect(response);
- if(content_type)
+ if (content_type)
{
ogs_sbi_header_set(response->http.headers, "Content-Type", content_type);
}
- if(location)
+ if (location)
{
ogs_sbi_header_set(response->http.headers, "Location", location);
}
- if(last_modified)
+ if (last_modified)
{
ogs_sbi_header_set(response->http.headers, "Last-Modified", get_time(last_modified));
}
- if(etag)
+ if (etag)
{
ogs_sbi_header_set(response->http.headers, "ETag", etag);
}
- if(cache_control)
+ if (cache_control)
{
char *response_cache_control;
response_cache_control = ogs_msprintf("max-age=%d", cache_control);
@@ -64,7 +65,7 @@ ogs_sbi_response_t *nf_server_new_response(char *location, char *content_type, t
ogs_free(response_cache_control);
}
- if(allow_methods)
+ if (allow_methods)
{
ogs_sbi_header_set(response->http.headers, "Allow", allow_methods);
@@ -128,7 +129,7 @@ bool nf_server_send_error(ogs_sbi_stream_t *stream,
memset(&problem, 0, sizeof(problem));
- if(problem_detail) {
+ if (problem_detail) {
problem_details = OpenAPI_problem_details_parseFromJSON(problem_detail);
problem.invalid_params = problem_details->invalid_params;
diff --git a/src/5gmsaf/server.h b/src/5gmsaf/server.h
index 63a286c..38323d0 100644
--- a/src/5gmsaf/server.h
+++ b/src/5gmsaf/server.h
@@ -1,11 +1,11 @@
/*
-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 NF_SERVER_H
@@ -33,10 +33,12 @@ extern bool nf_server_send_error(ogs_sbi_stream_t *stream,
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 *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);
+extern ogs_sbi_response_t *nf_server_new_response(const char *location, const char *content_type, time_t last_modified,
+ const char *etag, int cache_control, const 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
}
diff --git a/src/5gmsaf/service-access-information.c b/src/5gmsaf/service-access-information.c
index 8514683..f4c26b4 100644
--- a/src/5gmsaf/service-access-information.c
+++ b/src/5gmsaf/service-access-information.c
@@ -1,12 +1,14 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-Copyright: (C) 2022-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Authors: Dev Audsin
+ * David Waring
+ * Vuk Stojkovic
+ * Copyright: (C) 2022-2024 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
#include
@@ -19,12 +21,13 @@ program. If this file is missing then the license can be retrieved from
#include "provisioning-session.h"
#include "sai-cache.h"
#include "utilities.h"
-
#include "openapi/model/msaf_api_consumption_reporting_configuration.h"
#include "openapi/model/msaf_api_content_hosting_configuration.h"
#include "openapi/model/msaf_api_m5_media_entry_point.h"
#include "openapi/model/msaf_api_provisioning_session.h"
#include "openapi/model/msaf_api_service_access_information_resource.h"
+#include "metrics-reporting-configuration.h"
+
#include "service-access-information.h"
@@ -40,6 +43,7 @@ msaf_context_service_access_information_create(msaf_provisioning_session_t *prov
msaf_api_service_access_information_resource_client_consumption_reporting_configuration_t *ccrc = NULL;
msaf_api_service_access_information_resource_network_assistance_configuration_t *nac = NULL;
OpenAPI_list_t *entry_points = NULL;
+ OpenAPI_list_t *cmrc_list = NULL;
/* streaming entry points */
ogs_debug("Adding streams to ServiceAccessInformation [%s]", provisioning_session->provisioningSessionId);
@@ -56,12 +60,12 @@ msaf_context_service_access_information_create(msaf_provisioning_session_t *prov
OpenAPI_lnode_t *prof_node;
m5_profiles = OpenAPI_list_create();
OpenAPI_list_for_each(dist_conf->entry_point->profiles, prof_node) {
- OpenAPI_list_add(m5_profiles, ogs_strdup(prof_node->data));
+ OpenAPI_list_add(m5_profiles, msaf_strdup(prof_node->data));
}
}
url = ogs_msprintf("%s%s", dist_conf->base_url, dist_conf->entry_point->relative_path);
- m5_entry = msaf_api_m5_media_entry_point_create(url, ogs_strdup(dist_conf->entry_point->content_type), m5_profiles);
+ m5_entry = msaf_api_m5_media_entry_point_create(url, msaf_strdup(dist_conf->entry_point->content_type), m5_profiles);
ogs_assert(m5_entry);
if (!entry_points) entry_points = OpenAPI_list_create();
OpenAPI_list_add(entry_points, m5_entry);
@@ -74,7 +78,7 @@ msaf_context_service_access_information_create(msaf_provisioning_session_t *prov
if (provisioning_session->policy_templates) {
OpenAPI_list_t *policy_templates_svr_list;
OpenAPI_list_t *policy_template_bindings;
- msaf_api_sdf_method_e sdf_method = msaf_api_sdf_method__5_TUPLE;
+ msaf_api_sdf_method_e sdf_method = msaf_api_sdf_method_VAL__5_TUPLE;
OpenAPI_list_t *sdf_methods;
policy_template_bindings = _policy_templates_hash_to_list_of_ready_bindings(provisioning_session->policy_templates);
@@ -91,7 +95,7 @@ msaf_context_service_access_information_create(msaf_provisioning_session_t *prov
sdf_methods = OpenAPI_list_create();
ogs_assert(sdf_methods);
OpenAPI_list_add(sdf_methods, (void *)sdf_method);
-
+
dpic = msaf_api_service_access_information_resource_dynamic_policy_invocation_configuration_create(
policy_templates_svr_list, policy_template_bindings, sdf_methods);
} else {
@@ -128,6 +132,76 @@ msaf_context_service_access_information_create(msaf_provisioning_session_t *prov
ogs_assert(ccrc);
}
+ /* client metrics reporting configuration */
+ if (ogs_hash_count(provisioning_session->metrics_reporting_map) > 0) {
+
+ ogs_debug("Adding clientMetricsReporting to ServiceAccessInformation [%s]",
+ provisioning_session->provisioningSessionId);
+
+ cmrc_list = OpenAPI_list_create();
+ ogs_assert(cmrc_list);
+
+ ogs_hash_index_t *hi = NULL;
+ void *val = NULL;
+ const void *key = NULL;
+
+ for (hi = ogs_hash_first(provisioning_session->metrics_reporting_map); hi; hi = ogs_hash_next(hi)) {
+
+ ogs_hash_this(hi, &key, NULL, &val);
+
+ const msaf_metrics_reporting_configuration_t *metrics_config = (msaf_metrics_reporting_configuration_t *)val;
+
+ char *server_url = ogs_msprintf("http%s://%s/3gpp-m5/v2/", is_tls?"s":"", svr_hostname);
+ OpenAPI_list_t *cmrc_svr_list = OpenAPI_list_create();
+ ogs_assert(cmrc_svr_list);
+ OpenAPI_list_add(cmrc_svr_list, server_url);
+
+ OpenAPI_list_t *url_filters = NULL;
+ if (metrics_config->config->url_filters) {
+ url_filters = OpenAPI_list_create();
+ ogs_assert(url_filters);
+ OpenAPI_lnode_t *url_filt_node;
+ OpenAPI_list_for_each(metrics_config->config->url_filters, url_filt_node) {
+ OpenAPI_list_add(url_filters, msaf_strdup((const char*)url_filt_node->data));
+ }
+ }
+
+ OpenAPI_list_t *metrics = NULL;
+ if (metrics_config->config->metrics) {
+ metrics = OpenAPI_list_create();
+ ogs_assert(metrics);
+ OpenAPI_lnode_t *metrics_node;
+ OpenAPI_list_for_each(metrics_config->config->metrics, metrics_node) {
+ OpenAPI_list_add(metrics, msaf_strdup((const char*)metrics_node->data));
+ }
+ }
+
+ char *scheme = msaf_strdup(metrics_config->config->scheme);
+ if (!scheme || strlen(scheme) == 0) {
+ if (scheme) ogs_free(scheme);
+ scheme = msaf_strdup("urn:3GPP:ns:PSS:DASH:QM10");
+ }
+
+ msaf_api_service_access_information_resource_client_metrics_reporting_configurations_inner_t *cmrc_inner =
+ msaf_api_service_access_information_resource_client_metrics_reporting_configurations_inner_create(
+ msaf_strdup(metrics_config->config->metrics_reporting_configuration_id),
+ cmrc_svr_list,
+ NULL,
+ scheme,
+ msaf_strdup(metrics_config->config->data_network_name),
+ !!metrics_config->config->reporting_interval,
+ metrics_config->config->reporting_interval?*metrics_config->config->reporting_interval:0,
+ metrics_config->config->sample_percentage,
+ url_filters,
+ metrics_config->config->sampling_period?*metrics_config->config->sampling_period:0,
+ metrics);
+
+ if (cmrc_inner) {
+ OpenAPI_list_add(cmrc_list, cmrc_inner);
+ }
+ }
+ }
+
/* Network Assistance Configuration */
if (config->offerNetworkAssistance) {
OpenAPI_list_t *na_svr_list;
@@ -142,11 +216,11 @@ msaf_context_service_access_information_create(msaf_provisioning_session_t *prov
/* Create SAI */
service_access_information = msaf_api_service_access_information_resource_create(
msaf_strdup(provisioning_session->provisioningSessionId),
- msaf_api_provisioning_session_type_DOWNLINK,
+ msaf_api_provisioning_session_type_VAL_DOWNLINK,
streaming_access,
ccrc /* client_consumption_reporting_configuration */,
dpic /* dynamic_policy */,
- NULL /* client_metrics_reporting */,
+ cmrc_list /* OpenAPI_list_t client_metrics_reporting */,
nac /* network_assistance_configuration */,
NULL /* client_edge_resources */);
@@ -161,8 +235,8 @@ const msaf_sai_cache_entry_t *msaf_context_retrieve_service_access_information(c
const msaf_sai_cache_entry_t *sai_entry = NULL;
provisioning_session_context = msaf_provisioning_session_find_by_provisioningSessionId(provisioning_session_id);
- if (provisioning_session_context == NULL){
- ogs_error("Couldn't find the Provisioning Session ID [%s]", provisioning_session_id);
+ if (provisioning_session_context == NULL) {
+ ogs_error("Couldn't find the Provisioning Session ID [%s]", provisioning_session_id);
return NULL;
}
@@ -185,13 +259,14 @@ const msaf_sai_cache_entry_t *msaf_context_retrieve_service_access_information(c
ogs_debug("Found existing SAI cache entry");
}
- if (sai_entry == NULL){
+ if (sai_entry == NULL) {
ogs_error("The provisioning Session [%s] does not have an associated Service Access Information", provisioning_session_id);
}
return sai_entry;
}
+
static OpenAPI_list_t *_policy_templates_hash_to_list_of_ready_bindings(ogs_hash_t *policy_templates)
{
msaf_policy_template_node_t *policy_template_node;
@@ -204,7 +279,7 @@ static OpenAPI_list_t *_policy_templates_hash_to_list_of_ready_bindings(ogs_hash
for (hi = ogs_hash_first(policy_templates);
hi; hi = ogs_hash_next(hi)) {
policy_template_node = (msaf_policy_template_node_t *)ogs_hash_this_val(hi);
- if (policy_template_node->policy_template->state == msaf_api_policy_template_STATE_READY) {
+ if (policy_template_node->policy_template->state == msaf_api_policy_template_STATE_VAL_READY) {
policy_template_binding = msaf_api_service_access_information_resource_dynamic_policy_invocation_configuration_policy_template_bindings_inner_create(msaf_strdup(policy_template_node->policy_template->external_reference), msaf_strdup(policy_template_node->policy_template->policy_template_id));
OpenAPI_list_add(policy_template_bindings, policy_template_binding);
}
diff --git a/src/5gmsaf/service-access-information.h b/src/5gmsaf/service-access-information.h
index 0e8b215..8a411de 100644
--- a/src/5gmsaf/service-access-information.h
+++ b/src/5gmsaf/service-access-information.h
@@ -1,12 +1,12 @@
/*
-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_SERVICE_ACCESS_INFORMATION_H
#define MSAF_SERVICE_ACCESS_INFORMATION_H
diff --git a/src/5gmsaf/timer.c b/src/5gmsaf/timer.c
index cdd948f..ac9eaa2 100644
--- a/src/5gmsaf/timer.c
+++ b/src/5gmsaf/timer.c
@@ -2,7 +2,8 @@
* Copyright (C) 2019-2022 by Sukchan Lee
* Copyright (C) 2023 British Broadcasting Corporation
*
- * Authors: Sukchan Lee & Dev Audsin
+ * Authors: Sukchan Lee
+ * Dev Audsin
*
* This file is derived from Open5GS with additions by the BBC for 5G-MAG.
*
@@ -42,7 +43,7 @@ const char *msaf_timer_get_name(int timer_id)
return OGS_TIMER_NAME_SBI_CLIENT_WAIT;
case MSAF_TIMER_DELIVERY_BOOST:
return "MSAF_TIMER_DELIVERY_BOOST";
- default:
+ default:
break;
}
diff --git a/src/5gmsaf/timer.h b/src/5gmsaf/timer.h
index 20da124..bfc8c01 100644
--- a/src/5gmsaf/timer.h
+++ b/src/5gmsaf/timer.h
@@ -1,12 +1,12 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Author: Dev Audsin
+ * 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 MSAF_TIMER_H
#define MSAF_TIMER_H
diff --git a/src/5gmsaf/utilities.c b/src/5gmsaf/utilities.c
index cee9a8a..f8b0cf5 100644
--- a/src/5gmsaf/utilities.c
+++ b/src/5gmsaf/utilities.c
@@ -1,12 +1,13 @@
/*
-License: 5G-MAG Public License (v1.0)
-Author: Dev Audsin
-Copyright: (C) 2022-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
-*/
+ * License: 5G-MAG Public License (v1.0)
+ * Author: Dev Audsin
+ * David Waring
+ * Copyright: (C) 2022-2024 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 _GNU_SOURCE
#define _GNU_SOURCE
@@ -29,7 +30,7 @@ time_t str_to_time(const 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);
+ time = mktime(&tm);
return time;
}
@@ -39,7 +40,7 @@ const char *get_time(time_t time_epoch)
static char buf[80];
/* Format and print the time, "ddd yyyy-mm-dd hh:mm:ss zzz" */
- ts = localtime(&time_epoch);
+ ts = localtime(&time_epoch);
strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %Z", ts);
return buf;
@@ -71,13 +72,13 @@ 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;
@@ -92,7 +93,7 @@ char *get_path(const char *file)
char *file_dir = NULL;
path = realpath(file, NULL);
- if(path == NULL){
+ if (path == NULL) {
ogs_error("cannot find file with name[%s]: %s", file, strerror(errno));
return NULL;
}
@@ -128,7 +129,7 @@ long int ascii_to_long(const char *str)
return ret;
}
-uint16_t ascii_to_uint16(const char *str)
+uint16_t ascii_to_uint16(const char *str)
{
long int ret;
ret = ascii_to_long(str);
diff --git a/src/5gmsaf/utilities.h b/src/5gmsaf/utilities.h
index 5e6e899..1563344 100644
--- a/src/5gmsaf/utilities.h
+++ b/src/5gmsaf/utilities.h
@@ -2,7 +2,7 @@
* License: 5G-MAG Public License (v1.0)
* Author: Dev Audsin
* Copyright: (C) 2022-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
diff --git a/subprojects/.gitignore b/subprojects/.gitignore
index f391ce9..02bb91c 100644
--- a/subprojects/.gitignore
+++ b/subprojects/.gitignore
@@ -2,4 +2,5 @@ freeDiameter
libtins
prometheus-client-c
usrsctp
+open5gs
rt-5gc-service-consumers
diff --git a/subprojects/open5gs b/subprojects/open5gs
deleted file mode 160000
index 99f7da1..0000000
--- a/subprojects/open5gs
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 99f7da154e0fc4a494b35d1e74c26d89b934d5bc
diff --git a/subprojects/open5gs.wrap b/subprojects/open5gs.wrap
new file mode 100644
index 0000000..3ec0744
--- /dev/null
+++ b/subprojects/open5gs.wrap
@@ -0,0 +1,5 @@
+[wrap-git]
+directory = open5gs
+url = https://github.com/5G-MAG/open5gs.git
+revision = bbc-patches
+diff_files = open5gs.patch
diff --git a/subprojects/patch_open5gs.sh b/subprojects/packagefiles/open5gs.patch
similarity index 70%
rename from subprojects/patch_open5gs.sh
rename to subprojects/packagefiles/open5gs.patch
index 4dce785..791e476 100755
--- a/subprojects/patch_open5gs.sh
+++ b/subprojects/packagefiles/open5gs.patch
@@ -1,49 +1,3 @@
-#!/bin/sh
-#==============================================================================
-# 5G-MAG Reference Tools - Open5GS apply patches
-#==============================================================================
-# Author: David Waring
-# License: 5G-MAG Public License (v1.0)
-# Copyright: ©2022-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
-#==============================================================================
-
-cd `dirname "$0"`
-
-open5gs_src=`realpath "$1"`
-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 <stream_list, stream);
-diff --git a/lib/sbi/openapi/meson.build b/lib/sbi/openapi/meson.build
-index b3a507bd3..5f6388a0f 100644
---- a/lib/sbi/openapi/meson.build
-+++ b/lib/sbi/openapi/meson.build
-@@ -1370,6 +1370,7 @@ libsbi_openapi_sources = files('''
- '''.split())
-
- libsbi_openapi_inc = include_directories('.')
-+libsbi_openapi_model_inc = include_directories('model')
-
- sbi_openapi_cc_flags = ['-DOGS_SBI_COMPILATION']
-
diff --git a/lib/sbi/server.c b/lib/sbi/server.c
index af5cb8aad..518420c5c 100644
--- a/lib/sbi/server.c
@@ -331,48 +273,3 @@ index c112f9330..53467171a 100644
void ogs_sbi_server_remove(ogs_sbi_server_t *server);
void ogs_sbi_server_remove_all(void);
-diff --git a/src/main.c b/src/main.c
-index 329d5b108..0f993a6a6 100644
---- a/src/main.c
-+++ b/src/main.c
-@@ -111,7 +111,7 @@ int main(int argc, const char *const argv[])
- bool enable_debug;
- bool enable_trace;
- } optarg;
-- const char *argv_out[argc];
-+ const char *argv_out[argc+1];
-
- memset(&optarg, 0, sizeof(optarg));
-
-diff --git a/src/meson.build b/src/meson.build
-index d313b6932..2e25dbd93 100644
---- a/src/meson.build
-+++ b/src/meson.build
-@@ -33,6 +33,8 @@ version_conf = configuration_data()
- version_conf.set_quoted('OPEN5GS_VERSION', package_version)
- configure_file(output : 'version.h', configuration : version_conf)
-
-+app_main_c = files(['main.c'])
-+
- subdir('mme')
- subdir('hss')
- subdir('sgwc')
-diff --git a/tests/common/application.c b/tests/common/application.c
-index 1bf1a0528..501693a45 100644
---- a/tests/common/application.c
-+++ b/tests/common/application.c
-@@ -26,8 +26,8 @@ static void run(int argc, const char *const argv[],
- int rv;
- bool user_config;
-
-- /* '-f sample-XXXX.conf -e error' is always added */
-- const char *argv_out[argc+4], *new_argv[argc+4];
-+ /* '-f sample-XXXX.conf -e error' + null is always added */
-+ const char *argv_out[argc+5], *new_argv[argc+5];
- int argc_out;
-
- char conf_file[OGS_MAX_FILEPATH_LEN];
-EOF
-)
-fi
-exit 0
diff --git a/subprojects/rt-common-shared b/subprojects/rt-common-shared
index cf65591..1210229 160000
--- a/subprojects/rt-common-shared
+++ b/subprojects/rt-common-shared
@@ -1 +1 @@
-Subproject commit cf65591eb802aa034872adc96d07e5bad39b4e05
+Subproject commit 12102299bb4775f9a8d10225d5e20c2a96422b9c
diff --git a/tests/msaf/sai-cache-test.c b/tests/msaf/sai-cache-test.c
index bfdf3d7..0c9a61f 100644
--- a/tests/msaf/sai-cache-test.c
+++ b/tests/msaf/sai-cache-test.c
@@ -65,7 +65,7 @@ static void test_sai_cache_add(abts_case *tc, void *data)
nac = msaf_api_service_access_information_resource_network_assistance_configuration_create(nac_addresses);
ABTS_PTR_NOTNULL(tc, nac);
- sai = msaf_api_service_access_information_resource_create(ogs_strdup("Provisioning-Session-Id"), msaf_api_provisioning_session_type_DOWNLINK, streams, NULL, NULL, NULL, nac, NULL);
+ sai = msaf_api_service_access_information_resource_create(ogs_strdup("Provisioning-Session-Id"), msaf_api_provisioning_session_type_VAL_DOWNLINK, streams, NULL, NULL, NULL, nac, NULL);
ABTS_PTR_NOTNULL(tc, sai);
ABTS_TRUE(tc, msaf_sai_cache_add(cache, true, "af.example.com:443", sai));
diff --git a/tools/meson.build b/tools/meson.build
index cd43e1e..2e7314b 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -6,19 +6,10 @@
# program. If this file is missing then the license can be retrieved from
# https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view
-pymod = import('python')
fs = import('fs')
-python3 = pymod.find_installation('python3')
-
support_scripts_dir = get_option('libexecdir') / 'rt-5gms'
-scripts = {
- 'python3/m1_sync_config.py': 'msaf-configuration',
- 'python3/m1_client_cli.py': 'm1-client',
- 'python3/m1_session_cli.py': 'm1-session'
-}
-
support_scripts = {
'bash/certmgr': 'self-signed-certmgr',
'bash/le-certmgr': 'lets-encrypt-certmgr'
@@ -26,11 +17,7 @@ support_scripts = {
self_signed_certmgr_runtime = support_scripts_dir / 'self-signed-certmgr'
-python3_modules = [
- 'python3/lib/rt_m1_client',
-]
-
-scripts_conf_data = configuration_data({'python_packages_dir': python3.get_install_dir()})
+scripts_conf_data = configuration_data()
script_conf_options = [
'prefix', 'bindir', 'libdir', 'libexecdir', 'localstatedir', 'sbindir',
'sysconfdir',
@@ -39,21 +26,7 @@ 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
-
-sh = find_program('sh')
-foreach pm : python3_modules
- mod_files = run_command([sh, '-c', 'cd "$MESON_SOURCE_ROOT/$MESON_SUBDIR/'+fs.parent(pm)+'"; find "' + fs.name(pm) + '" -type f -name "*.py" -print'], check: false).stdout().strip().split('\n')
- foreach mod_filepath : mod_files
- mod_file = files([fs.parent(pm) / mod_filepath])
- python3.install_sources(mod_file, subdir: fs.parent(mod_filepath))
- endforeach
-endforeach
diff --git a/tools/python3/lib/rt_m1_client/certificates/__init__.py b/tools/python3/lib/rt_m1_client/certificates/__init__.py
deleted file mode 100644
index 5fd896e..0000000
--- a/tools/python3/lib/rt_m1_client/certificates/__init__.py
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/python3
-#==============================================================================
-# 5G-MAG Reference Tools: M1 Client Certificate Signing
-#==============================================================================
-#
-# File: rt_m1_client/certificates/__init__.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 Module
-# =====================================
-#
-# 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
-# ACMECertificateSigner - A CertificateSigner which uses an ACME service to sign the certificates
-# LetsEncryptCertificateSigner - An ACMECertificateSigner preconfigured for Let's Encrypt service.
-# TestLetsEncryptCertificateSigner - An ACMECertificateSigner preconfigured for Let's Encrypt staging service.
-#
-# 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 .base import CertificateSigner
-from .local_ca_cert_signer import LocalCACertificateSigner
-from .acme_cert_signer import ACMECertificateSigner, LetsEncryptCertificateSigner, TestLetsEncryptCertificateSigner
-
-DefaultCertificateSigner = LocalCACertificateSigner
-
-__all__ = [
- "CertificateSigner",
- "LocalCACertificateSigner",
- "ACMECertificateSigner",
- "LetsEncryptCertificateSigner",
- "TestLetsEncryptCertificateSigner",
- "DefaultCertificateSigner",
- ]
diff --git a/tools/python3/lib/rt_m1_client/certificates/acme_cert_signer.py b/tools/python3/lib/rt_m1_client/certificates/acme_cert_signer.py
deleted file mode 100644
index 5697d4a..0000000
--- a/tools/python3/lib/rt_m1_client/certificates/acme_cert_signer.py
+++ /dev/null
@@ -1,173 +0,0 @@
-#!/usr/bin/python3
-#==============================================================================
-# 5G-MAG Reference Tools: ACME Certificate Signing
-#==============================================================================
-#
-# File: rt_acme_cert_signer/certsigner.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
-#
-#==============================================================================
-#
-# ACME Certificate Signing
-# ========================
-#
-# This module defines an rt_m1_client.certificates.CertificateSigner class that
-# will use an ACME service, such as Let's Encrypt, to generate signed
-# certificates.
-#
-# ACMECertificateSigner - ACME certificate signing class.
-#
-# LetsEncryptCertificateSigner - Helper function to create an ACMECertificateSigner for the live Let's Encrypt service.
-# TestLetsEncryptCertificateSigner - Helper function to create an ACMECertificateSigner for the staging Let's Encrypt service.
-#
-'''
-================================================
-5G-MAG Reference Tools: ACME Certificate Signing
-================================================
-
-This module defines an ACME `rt_m1_client.certificates.CertificateSigner` class
-that can be used by the `rt_m1_client.certificates.M1Session` class to provide
-certificate signing services which use an ACME service such as Let's Encrypt.
-'''
-
-# Python system modules
-import aiofiles
-import asyncio
-from cryptography.hazmat.primitives.serialization import Encoding as cryptography_Encoding, PublicFormat as cryptography_PublicFormat
-import logging
-import os.path
-import re
-from typing import Optional, List, Tuple
-
-# 3rd party modules
-import OpenSSL
-
-# Local modules
-from .base import CertificateSigner
-from ..data_store import DataStore
-
-LOGGER = logging.getLogger(__name__)
-
-class ACMECertificateSigner(CertificateSigner):
- '''ACMECertificateSigner class
-
- Class to perform certificate signing using an ACME certificate signing service.
-
- Constants
- =========
-
- - LetsEncryptService - URL of the Let's Encrypt live service
- - LetsEncryptStagingService - URL of the Let's Encrypt staging (test) service
- '''
-
- LetsEncryptStagingService: str = 'https://acme-staging-v02.api.letsencrypt.org/directory'
- LetsEncryptService: str = 'https://acme-v02.api.letsencrypt.org/directory'
-
- def __init__(self, *args, acme_service: Optional[str] = None, docroots_dir: Optional[str] = None, default_docroot_dir: Optional[str] = None, data_store: Optional[DataStore] = None, **kwargs):
- '''Constructor
-
- :param acme_service: The URL of the ACME directory service to use for certificate signing.
- :param docroots_dir: The directory that contains all the document roots for the virtual hosts, each host has a directory
- whose name is the FQDN of the virtual host.
- :param default_docroot_dir: The directory which is the docroot of the default virtual host.
- :param data_store: The persistent data store object to use for data persistence.
- '''
- errs=[]
- if acme_service is None:
- errs += ['acme_service is None']
- if docroots_dir is None:
- errs += ['docroots_dir is None']
- if default_docroot_dir is None:
- errs += ['default_docroot_dir is None']
- if len(errs) != 0:
- raise RuntimeError(f'{self.__class__.__name__} instantiated without needed parameters: {", ".join(errs)}')
- super().__init__(*args, data_store=data_store, **kwargs)
- self.__acme_service: str = acme_service
- self.__docroots: str = docroots_dir
- self.__default_docroot: str = default_docroot_dir
-
- 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, **kwargs) -> Optional[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.
-
- This will use the *csr* as a guideline for talking to the ACME server. The *domain_name_alias* will be used for the common name and first SAN, if the common name or SANs from the *csr* are not private IPs or localhost references then they will also be included.
- '''
- x509req: OpenSSL.crypto.X509Req = OpenSSL.crypto.load_certificate_request(OpenSSL.crypto.FILETYPE_PEM, csr.encode('utf-8'))
-
- # Send request to ACME server
- acmeReqBytes: bytes = OpenSSL.crypto.dump_certificate_request(OpenSSL.crypto.FILETYPE_PEM, x509req)
- async with aiofiles.tempfile.NamedTemporaryFile('wb', delete=False) as f:
- await f.write(acmeReqBytes)
- common_name = x509req.get_subject().commonName
- if isinstance(common_name,bytes):
- common_name = common_name.decode('utf-8')
- domain_docroot = os.path.join(self.__docroots, common_name)
- old_umask = os.umask(0)
- try:
- await aiofiles.os.makedirs(domain_docroot, mode=0o755, exist_ok=True)
- if not os.path.lexists(os.path.join(domain_docroot, '.well-known')):
- await aiofiles.os.symlink(os.path.join(self.__default_docroot, '.well-known'), os.path.join(domain_docroot, '.well-known'), target_is_directory=True)
- finally:
- os.umask(old_umask)
- async with aiofiles.tempfile.TemporaryDirectory() as d:
- result, output = await _run_certbot_app(['certonly', '--server', self.__acme_service, '--webroot', '--webroot-path', self.__default_docroot, '--csr', f.name, '--cert-path', os.path.join(d, 'certificate.pem'), '--fullchain-path', os.path.join(d, 'fullchain.pem'), '--chain-path', os.path.join(d, 'chain.pem')])
- certdata = None
- if result == 0:
- async with aiofiles.open(os.path.join(d, 'fullchain.pem'), 'r') as inpem:
- certdata = await inpem.read()
- else:
- log_error(f'certbot failed with exit code {result}: {output}')
- await aiofiles.os.remove(f.name)
- return certdata
-
-async def _run_certbot_app(cmd_args: List[str]) -> Tuple[int, bytes]:
- '''Run `certbot` using the given command line arguments
-
- :param cmd_args: The command line arguments for `certbot`.
-
- :return: A tuple of the `certbot` process exit code and STDOUT from `certbot`.
- '''
- LOGGER.debug('Executing: certbot %s', ' '.join(['\''+s+'\'' for s in cmd_args]))
- proc = await asyncio.create_subprocess_exec('certbot', *cmd_args, stdout=asyncio.subprocess.PIPE)
- await proc.wait()
- LOGGER.debug('Command exited with code %i', proc.returncode)
- data = await proc.stdout.read()
- return (proc.returncode, data)
-
-async def LetsEncryptCertificateSigner(*args, docroots_dir: Optional[str] = None, default_docroot_dir: Optional[str] = None, data_store: Optional[DataStore] = None, **kwargs) -> ACMECertificateSigner:
- '''Let's Encrypt ACMECertificateSigner factory function
-
- Creates an ACMECertificateSigner with *acme_service* set to the Let's Encrypt live service URL and other parameters passed through.
-
- :return: a new ACMECertificateSigner which will use Let's Encrypt.
- '''
- return await ACMECertificateSigner(*args, acme_service=ACMECertificateSigner.LetsEncryptService, docroots_dir=docroots_dir, default_docroot_dir=default_docroot_dir, data_store=data_store, **kwargs)
-
-async def TestLetsEncryptCertificateSigner(*args, docroots_dir: Optional[str] = None, default_docroot_dir: Optional[str] = None, data_store: Optional[DataStore] = None, **kwargs) -> ACMECertificateSigner:
- '''Let's Encrypt staging (test) service ACMECertificateSigner factory function
-
- Creates an ACMECertificateSigner with *acme_service* set to the Let's Encrypt staging service URL and other parameters passed through.
-
- :return: a new ACMECertificateSigner which will use Let's Encrypt staging service.
- '''
- return await ACMECertificateSigner(*args, acme_service=ACMECertificateSigner.LetsEncryptStagingService, docroots_dir=docroots_dir, default_docroot_dir=default_docroot_dir, data_store=data_store, **kwargs)
-
diff --git a/tools/python3/lib/rt_m1_client/certificates/base.py b/tools/python3/lib/rt_m1_client/certificates/base.py
deleted file mode 100644
index f748456..0000000
--- a/tools/python3/lib/rt_m1_client/certificates/base.py
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/python3
-#==============================================================================
-# 5G-MAG Reference Tools: M1 Client Certificate Signing base class
-#==============================================================================
-#
-# File: rt_m1_client/certificates/base.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 base class
-# =========================================
-#
-# This module defines classes used by the M1 session classes to sign certificates
-#
-# CertificateSigner - Base class for certificate signing.
-#
-'''
-=================================================================
-5G-MAG Reference Tools: M1 Session Certificate Signing base class
-=================================================================
-
-This module defines some classes that can be used by the `M1Session` class to provide certificate signing services.
-
-'''
-from typing import Optional
-
-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, **kwargs) -> Optional[str]:
- '''Sign a CSR in PEM format and return the public X509 Certificate in PEM format
-
- :param str csr: A CSR in PEM format.
-
- :return: a public X509 certificate in PEM format.
- '''
- raise NotImplementedError('Class derived from CertificateSigner must implement this method')
diff --git a/tools/python3/lib/rt_m1_client/certificates/local_ca_cert_signer.py b/tools/python3/lib/rt_m1_client/certificates/local_ca_cert_signer.py
deleted file mode 100644
index ed74784..0000000
--- a/tools/python3/lib/rt_m1_client/certificates/local_ca_cert_signer.py
+++ /dev/null
@@ -1,157 +0,0 @@
-#!/usr/bin/python3
-#==============================================================================
-# 5G-MAG Reference Tools: M1 Client Local CA Certificate Signing
-#==============================================================================
-#
-# File: rt_m1_client/certificates/local_ca_cert_signer.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 using a local CA
-# ===============================================
-#
-# This module defines classes used by the M1 session classes to sign certificates
-#
-# LocalCACertificateSigner - A CertificateSigner that uses a locally generated CA to generate X509 certificates from CSRs
-#
-'''
-=======================================================================
-5G-MAG Reference Tools: M1 Session Certificate Signing using a local CA
-=======================================================================
-
-This module defines some classes that can be used by the `M1Session` class to provide certificate signing services.
-
-'''
-from typing import Optional, Tuple, List
-
-import OpenSSL
-
-from .base import CertificateSigner
-from ..data_store import DataStore
-
-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):
- '''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: 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, **kwargs) -> Optional[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* and the commonName. 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.
-
- :return: a public X509 certificate in PEM format, or None on error.
- '''
- x509req: OpenSSL.crypto.X509Req = OpenSSL.crypto.load_certificate_request(OpenSSL.crypto.FILETYPE_PEM, csr.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())
- 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() not in [b'subjectKeyIdentifier', b'authorityKeyIdentifier', b'basicConstraints']:
- 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')
- ])
- 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) -> 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
- 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) -> 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')
- 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
diff --git a/tools/python3/lib/rt_m1_client/client.py b/tools/python3/lib/rt_m1_client/client.py
deleted file mode 100644
index c171973..0000000
--- a/tools/python3/lib/rt_m1_client/client.py
+++ /dev/null
@@ -1,893 +0,0 @@
-#!/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) 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 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, List
-
-import httpx
-
-from .exceptions import (M1ClientError, M1ServerError)
-from .types import (ApplicationId, ContentHostingConfiguration, ContentProtocols,
- ConsumptionReportingConfiguration, PolicyTemplate,
- 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):
- '''Response containing a ContentProtocols object
- '''
- ProvisioningSessionId: ResourceId
- ContentProtocols: ContentProtocols
-
-class ConsumptionReportingConfigurationResponse(TagAndDateResponse, total=False):
- '''Response containing a consumption reporting configuration
- '''
- ProvisioningSessionId: ResourceId
- ConsumptionReportingConfiguration: ConsumptionReportingConfiguration
-
-class PolicyTemplateResponse(TagAndDateResponse, total=False):
- '''Response containing a policy template
- '''
- ProvisioningSessionId: ResourceId
- PolicyTemplate: PolicyTemplate
-
-class M1Client:
- '''5G-MAG Reference Tools: M1 Client
- '''
-
- def __init__(self, host_address: Tuple[str,int]):
- '''
- Constructor
-
- :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
- self.__log = logging.getLogger(__name__ + '.' + self.__class__.__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
-
- :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.
-
- :return: the ResourceId of the allocated provisioning session or None if there was an error.
-
- :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)
- send: ProvisioningSession = {
- 'provisioningSessionType': provisioning_session_type,
- 'appId': 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
-
- :param ResourceId provisioning_session_id: The provisioning session to find.
-
- :return: a ProvisioningSessionResponse structure if the provisioning session was found, or None if the provisioning
- session was not found.
-
- :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, '',
- '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
-
- :param ResourceId provisioning_session_id: The provisioning session to find.
-
- :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.
- '''
- result = await self.__do_request('DELETE',
- '/provisioning-sessions/' + provisioning_session_id, '',
- 'application/json')
- if result['status_code'] == 204 or result['status_code'] == 202:
- 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
-
- :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',
- 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
-
- :param ResourceId provisioning_session_id: The provisioning session to fetch the current content hosting configuration
- for.
-
- :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',
- '', '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
- ) -> bool:
- '''
- Update a content hosting configuration for a provisioning session
-
- :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: ``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',
- json.dumps(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 patchContentHostingConfiguration(self, provisioning_session_id: ResourceId, patch: str
- ) -> Union[bool,ContentHostingConfigurationResponse]:
- '''
- Patch a content hosting configuration for a provisioning session using a JSON patch
-
- :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.
-
- :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',
-
- 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
-
- :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.
-
- :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',
- '', 'application/json')
- if result['status_code'] == 204 or result['status_code'] == 202:
- 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
-
- :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.
- :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:
- 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, extra_domain_names: Optional[List[str]] = None, csr: bool = False) -> Optional[ServerCertificateSigningRequestResponse]:
- '''Create or reserve a server certificate for a provisioing session
-
- :param ResourceId provisioning_session_id: The provisioning session to create the new certificate entry in.
- :param extra_domain_names: An optional list of extra domain names to include a CSR as SubjectAltName entries.
- :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. The *extra_domain_names* parameter may contain a list of extra domain names to include
- in the SubjectAltNames extension.
-
- If *csr* is ``False`` or not provided then create a new certificate and just return the new certificate Id. The
- *extra_domain_names* must be an empty list or ``None``.
-
- :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'
- if extra_domain_names is not None and not isinstance(extra_domain_names,list):
- raise M1ServerError(reason = f'Bad parameter passed during certificate creation', status_code = 500)
- if csr:
- url += '?csr=true'
- elif extra_domain_names is not None and len(extra_domain_names) > 0:
- raise M1ClientError(reason = f'Extra domain names cannot be specified when not generating a CSR', status_code = 400)
- body=''
- if extra_domain_names is not None and len(extra_domain_names) > 0:
- body = json.dumps(extra_domain_names)
- result = await self.__do_request('POST', url, body, 'application/json')
- 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
-
- :param ResourceId provisioning_session_id: The provisioning session to create the new certificate entry in.
-
- :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
-
- async def reserveServerCertificate(self, provisioning_session_id: ResourceId, extra_domain_names: Optional[List[str]] = None) -> ServerCertificateSigningRequestResponse:
- '''Reserve a certificate for a provisioning session and get the CSR PEM
-
- :param ResourceId provisioning_session_id: The provisioning session to create the new certificate entry in.
- :param extra_domain_names: An optional list of extra domain names to include as Subject Alt Names.
-
- :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, extra_domain_names=extra_domain_names, 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
-
- :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.
-
- :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}',
- 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
-
- :param ResourceId provisioning_session_id: The provisioning session for the certificate.
- :param ResourceId certificate_id: The certificate Id of the certificate.
-
- :return: a ServerCertificateResponse containing the PEM data for the public certificate and its metadata or ``None``
- if the certificate is reserved and awaiting upload.
-
- :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}',
- '', '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.
-
- :param ResourceId provisioning_session_id: The provisioning session for the certificate.
- :param ResourceId certificate_id: The certificate Id of the certificate.
-
- :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}',
- '', 'application/octet-stream')
- if result['status_code'] == 204 or result['status_code'] == 202:
- 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
-
- :param ResourceId provisioning_session_id: The provisioning session to get the ContentProtocols for.
-
- :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',
- '', '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 activateConsumptionReportingConfiguration(self, provisioning_session_id: ResourceId, consumption_reporting_config: ConsumptionReportingConfiguration) -> Union[Optional[ConsumptionReportingConfigurationResponse],bool]:
- '''Set the ConsumptionReportingConfiguration for the provisioning session
-
- :param ResourceId provisioning_session_id: The provisioning session to set the ConsumptionReportingConfiguration for.
- :param ConsumptionReportingConfiguration consumption_reporting_config: The ConsumptionReportingConfiguration to set.
-
- :return: `True` if the ConsumptionReportingConfiguration was set and the Application Function didn't report back the
- configuration, or a `ConsumptionReportingConfigurationResponse` if the configuration was reported back, or `None`
- if setting the configuration 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('POST',
- f'/provisioning-sessions/{provisioning_session_id}/consumption-reporting-configuration',
- json.dumps(consumption_reporting_config), 'application/json')
- if result['status_code'] == 200:
- ret: ConsumptionReportingConfigurationResponse = self.__tag_and_date(result)
- ret['ConsumptionReportingConfiguration'] = ConsumptionReportingConfiguration.fromJSON(result['body'])
- return ret
- elif result['status_code'] == 204:
- return True
- self.__default_response(result)
- return None
-
- async def retrieveConsumptionReportingConfiguration(self, provisioning_session_id: ResourceId) -> Optional[ConsumptionReportingConfigurationResponse]:
- '''Get the ConsumptionReportingConfiguration for the provisioning session
-
- :param ResourceId provisioning_session_id: The provisioning session to get the ConsumptionReportingConfiguration for.
-
- :return: A `ConsumptionReportingConfigurationResponse` for the current configuration in 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('GET',
- f'/provisioning-sessions/{provisioning_session_id}/consumption-reporting-configuration',
- '', 'application/octet-stream')
- if result['status_code'] == 200:
- ret: ConsumptionReportingConfigurationResponse = self.__tag_and_date(result)
- ret['ConsumptionReportingConfiguration'] = ConsumptionReportingConfiguration.fromJSON(result['body'])
- return ret
- if result['status_code'] == 404:
- return None
- self.__default_response(result)
- return None
-
- async def updateConsumptionReportingConfiguration(self, provisioning_session_id: ResourceId, consumption_reporting_config: ConsumptionReportingConfiguration) -> bool:
- '''Modify the ConsumptionReportingConfiguration for the provisioning session
-
- :param ResourceId provisioning_session_id: The provisioning session to modify the ConsumptionReportingConfiguration for.
- :param ConsumptionReportingConfiguration consumption_reporting_config: The ConsumptionReportingConfiguration to apply.
-
- :return: `True` if the configuration was changed successfully.
-
- :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}/consumption-reporting-configuration',
- json.dumps(consumption_reporting_config), 'application/json')
- if result['status_code'] == 204:
- return True
- self.__default_response(result)
- return False
-
- async def patchConsumptionReportingConfiguration(self, provisioning_session_id: ResourceId, patch: str) -> ConsumptionReportingConfigurationResponse:
- '''Patch the ConsumptionReportingConfiguration for the provisioning session
-
- :param ResourceId provisioning_session_id: The provisioning session to modify the ConsumptionReportingConfiguration for.
- :param str patch: The JSON patch to apply to the ConsumptionReportingConfiguration.
-
- :return: A `ConsumptionReportingConfigurationResponse` containing the new configuration after the patch is applied.
-
- :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}/consumption-reporting-configuration',
- patch, 'application/json-patch+json')
- if result['status_code'] == 200:
- ret: ConsumptionReportingConfigurationResponse = self.__tag_and_date(result)
- ret['ConsumptionReportingConfiguration'] = ConsumptionReportingConfiguration.fromJSON(result['body'])
- return ret
- self.__default_response(result)
- return None
-
- async def destroyConsumptionReportingConfiguration(self, provisioning_session_id: ResourceId) -> bool:
- '''Remove the ConsumptionReportingConfiguration from the provisioning session
-
- :param ResourceId provisioning_session_id: The provisioning session to remove the ConsumptionReportingConfiguration from.
-
- :return: `True` if the ConsumptionReportingConfiguration was successfully removed.
-
- :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}/consumption-reporting-configuration',
- '', 'application/octet-stream')
- if result['status_code'] == 204:
- return True
- self.__default_response(result)
- return False
-
- # 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[PolicyTemplateResponse]:
- '''Create a new PolicyTemplate in a provisioning session
-
- :param ResourceId provisioning_session_id: The provisioning session to add the PolicyTemaplet to.
- :param PolicyTemplate policy_template: The PolicyTemplate to add to the provisioning session.
- :return: The PolicyTemplateResponse if successful.
- :raise M1ClientError: if there was a problem with the request.
- :raise M1ServerError: if there was a server side issue preventing the creation of the policy template.
- '''
- result = await self.__do_request('POST',
- f'/provisioning-sessions/{provisioning_session_id}/policy-templates',
- json.dumps(policy_template), 'application/json')
- if result['status_code'] == 200:
- ret: PolicyTemplateResponse = self.__tag_and_date(result)
- ret['PolicyTemplate'] = PolicyTemplate.fromJSON(result['body'])
- return ret
- if result['status_code'] == 201 or result['status_code'] == 204:
- pol_temp_id: ResourceId = result['headers'].get('location').rsplit('/',1)[-1]
- return await self.retrievePolicyTemplate(provisioning_session_id, pol_temp_id)
- self.__default_response(result)
- return None
-
- async def retrievePolicyTemplate(self, provisioning_session_id: ResourceId, policy_template_id: ResourceId) -> Optional[PolicyTemplateResponse]:
- '''Retrieve a PolicyTemplate for a provisioning session
-
- :param ResourceId provisioning_session_id: The provisioning session to retrieve the PolicyTemplate from.
- :param ResourceId policy_template_id: The PolicyTemplate Id of the PolicyTemplate to retrieve.
- :return: A `PolicyTemplateResponse` which holds the `PolicyTemplate` and the caching metadata or `None` if the
- `PolicyTemplate` cannot be found.
- :raise M1ClientError: if there was a problem with the request.
- :raise M1ServerError: if there was a server side issue preventing the retrieval of the policy template.
- '''
- result = await self.__do_request('GET',
- f'/provisioning-sessions/{provisioning_session_id}/policy-templates/{policy_template_id}',
- '', 'application/json')
- if result['status_code'] == 200:
- ret: PolicyTemplateResponse = self.__tag_and_date(result)
- ret['PolicyTemplate'] = PolicyTemplate.fromJSON(result['body'])
- return ret
- if result['status_code'] == 404:
- return None
- self.__default_response(result)
- return None
-
- async def updatePolicyTemplate(self, provisioning_session_id: ResourceId, policy_template_id: ResourceId, policy_template: PolicyTemplate) -> bool:
- '''Update an existing PolicyTemplate in a provisioning session
-
- :param ResourceId provisioning_session_id: The provisioning session to replace the PolicyTemplate in.
- :param ResourceId policy_template_id: The PolicyTemplate Id of the PolicyTemplate to replace.
- :param PolicyTemplate policy_template: The PolicyTemplate which will replace the existing one in the provisioning session.
- :return: `True` if the update succeeded.
- :raise M1ClientError: if there was a problem with the request.
- :raise M1ServerError: if there was a server side issue preventing the update of the policy template.
- '''
- result = await self.__do_request('PUT',
- f'/provisioning-sessions/{provisioning_session_id}/policy-templates/{policy_template_id}',
- json.dumps(policy_template), 'application/json')
- if result['status_code'] == 204:
- return True
- if result['status_code'] == 404:
- return False
- self.__default_response(result)
- return False
-
- async def patchPolicyTemplate(self, provisioning_session_id: ResourceId, policy_template_id: ResourceId, patch: str) -> Optional[PolicyTemplateResponse]:
- '''Patch a PolicyTemplate for the provisioning session
-
- :param ResourceId provisioning_session_id: The provisioning session to modify the PolicyTemplate for.
- :param ResourceId policy_template_id: The PolicyTemplateId for the PolicyTemplate in the provisioning session.
- :param str patch: The JSON patch to apply to the ConsumptionReportingConfiguration.
-
- :return: A `PolicyTemplateResponse` containing the new template after the patch is applied.
-
- :raise M1ClientError: if there was a problem with the request.
- :raise M1ServerError: if there was a server side issue preventing the patching of the policy template.
- '''
- result = await self.__do_request('PATCH',
- f'/provisioning-sessions/{provisioning_session_id}/policy-templates/{policy_template_id}',
- patch, 'application/json-patch+json')
- if result['status_code'] == 200:
- ret: PolicyTemplateResponse = self.__tag_and_date(result)
- ret['PolicyTemplate'] = PolicyTemplate.fromJSON(result['body'])
- return ret
- if result['status_code'] == 404:
- return None
- self.__default_response(result)
- return None
-
- async def destroyPolicyTemplate(self, provisioning_session_id: ResourceId, policy_template_id: ResourceId) -> bool:
- '''Destroy a PolicyTemplate in a provisioning session
-
- :param ResourceId provisioning_session_id: The provisioning session to modify the PolicyTemplate for.
- :param ResourceId policy_template_id: The PolicyTemplateId for the PolicyTemplate in the provisioning session.
-
- :return: `True` if the PolicyTemplate was deleted or `False` if the PolicyTemplate didn't exist.
-
- :raise M1ClientError: if there was a problem with the request.
- :raise M1ServerError: if there was a server side issue preventing the deletion of the provisioning session.
- '''
- result = await self.__do_request('DELETE',
- f'/provisioning-sessions/{provisioning_session_id}/policy-templates/{policy_template_id}',
- '', 'application/json')
- if result['status_code'] == 204:
- return True
- if result['status_code'] == 404:
- return False
- self.__default_response(result)
- return False
-
- # 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
-
- :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):
- 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
-
- 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']),
- 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:
- '''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
- 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
- # 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) -> 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__ = [
- # Types
- 'ProvisioningSessionResponse',
- 'ContentHostingConfigurationResponse',
- 'ConsumptionReportingConfigurationResponse',
- 'ServerCertificateResponse',
- 'ServerCertificateSigningRequestResponse',
- 'ContentProtocolsResponse',
- 'PolicyTemplateResponse',
- # Classes
- 'M1Client',
- ]
diff --git a/tools/python3/lib/rt_m1_client/configuration.py b/tools/python3/lib/rt_m1_client/configuration.py
deleted file mode 100644
index 99f4497..0000000
--- a/tools/python3/lib/rt_m1_client/configuration.py
+++ /dev/null
@@ -1,179 +0,0 @@
-#!/usr/bin/python3
-#==============================================================================
-# 5G-MAG Reference Tools: M1 Session Configuration
-#==============================================================================
-#
-# File: rt_m1_client/configuration.py
-# License: 5G-MAG Public License (v1.0)
-# Author: David Waring
-# Copyright: (C) 2022-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 Configuration class
-# ==============================
-#
-# This module contains a configuration class which hold application
-# configuration for programs which use the M1 Session class.
-#
-'''5G-MAG Reference Tools: M1 Session Configuration
-================================================
-
-'''
-import configparser
-import os
-import os.path
-
-from typing import List
-
-class Configuration:
- '''Application configuration container
-
- This class handles the loading and saving of the application 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 = 127.0.0.23
- 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'))
- 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:
- '''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'
- else:
- section = 'm1-client'
- self.__config.set(section, key, value)
- self.__saveConfig()
- 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):
- old_umask = os.umask(0)
- try:
- os.makedirs(cfgdir, mode=0o755)
- finally:
- os.umask(old_umask)
- 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):
- '''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}")'
-
-__all__ = [
- # Classes
- 'Configuration',
- ]
diff --git a/tools/python3/lib/rt_m1_client/data_store.py b/tools/python3/lib/rt_m1_client/data_store.py
deleted file mode 100644
index 3f4bc41..0000000
--- a/tools/python3/lib/rt_m1_client/data_store.py
+++ /dev/null
@@ -1,148 +0,0 @@
-#!/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 aiofiles
-import aiofiles.os
-import json
-import logging
-import os
-import os.path
-from typing import Any
-
-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')
-
-class JSONFileDataStore(DataStore):
- '''JSONFileDataStore class
-
- 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):
- old_umask = os.umask(0)
- try:
- await aiofiles.os.makedirs(self.__dir, mode=0o700)
- finally:
- os.umask(old_umask)
- 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
-
- :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):
- return default
- 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:
- '''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:
- await json_out.write(json.dumps(value))
- return True
diff --git a/tools/python3/lib/rt_m1_client/exceptions.py b/tools/python3/lib/rt_m1_client/exceptions.py
deleted file mode 100644
index 0b2e41c..0000000
--- a/tools/python3/lib/rt_m1_client/exceptions.py
+++ /dev/null
@@ -1,135 +0,0 @@
-#!/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) -> 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:
- 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):
- '''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 = ''
- 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
- # 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:
- '''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
- 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 at a future date and may or may not work then.
- '''
-
-__all__ = [
- "M1Error",
- "M1ClientError",
- "M1ServerError",
- ]
diff --git a/tools/python3/lib/rt_m1_client/session.py b/tools/python3/lib/rt_m1_client/session.py
deleted file mode 100644
index 4e5bbca..0000000
--- a/tools/python3/lib/rt_m1_client/session.py
+++ /dev/null
@@ -1,970 +0,0 @@
-#!/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) 2022-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 datetime
-import importlib
-import inspect
-import logging
-import re
-from typing import Optional, Union, Tuple, Dict, Any, TypedDict, List, Iterable
-
-import OpenSSL
-
-from .exceptions import (M1ClientError, M1ServerError, M1Error)
-from .types import (ApplicationId, ContentHostingConfiguration, ContentProtocols, ProvisioningSessionType, ProvisioningSession,
- ConsumptionReportingConfiguration, ResourceId, PolicyTemplate, PROVISIONING_SESSION_TYPE_DOWNLINK)
-from .client import (M1Client, ProvisioningSessionResponse, ContentHostingConfigurationResponse, ServerCertificateResponse,
- ServerCertificateSigningRequestResponse, ContentProtocolsResponse, ConsumptionReportingConfigurationResponse,
- PolicyTemplateResponse)
-from .data_store import DataStore
-from .certificates import CertificateSigner, DefaultCertificateSigner
-
-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. 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
- 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):
- '''``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) -> 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
- 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]]:
- '''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
- 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]:
- '''Get the 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
- 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
-
- 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()
- result = await self.__m1_client.destroyProvisioningSession(provisioning_session_id)
- 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()))
- 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.
-
- :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: 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
-
- 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:
- entry_points = [dc['entryPoint'] for dc in ps['content-hosting-configuration']['contenthostingconfiguration']['distributionConfigurations'] if 'entryPoint' in dc]
- entry_point_paths = [e['relativePath'] for e in entry_points]
- if (entrypoint is None and len(entry_point_paths) == 0) or (entrypoint is not None and entrypoint in entry_point_paths):
- ret = ps_id
- break
- return ret
-
- # 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)
- ps = self.__provisioning_sessions[provisioning_session_id]['provisioningsession']
- if 'serverCertificateIds' not in ps:
- return []
- 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()
- 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:
- # 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]:
- '''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, extra_domain_names: Optional[List[str]] = None) -> 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.
- :param extra_domain_names: An optional list of extra domain names to add as SubjectAltName entries in a CSR.
-
- :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()
- cert_resp: ServerCertificateSigningRequestResponse = await self.__m1_client.reserveServerCertificate(
- provisioning_session_id, extra_domain_names=extra_domain_names)
- 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'])
-
- 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()
- return await self.__m1_client.uploadServerCertificate(provisioning_session_id, certificate_id, pem)
-
- # 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()
- 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]:
- '''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)
- ps = await self.__getProvisioningSessionCache(provisioning_session)
- if ps is None or ps['content-hosting-configuration'] is None:
- 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)
-
- # ConsumptionReportingConfiguration methods
-
- async def consumptionReportingConfigurationCreate(self, provisioning_session: ResourceId, crc: ConsumptionReportingConfiguration) -> bool:
- '''Store a new `ConsumptionReportingConfiguration` for a provisioning session
-
- :param provisioning_session: The provisioning session id of the provisioning session to set the
- `ConsumptionReportingConfiguration` in.
- :param crc: The `ConsumptionReportingConfiguration` to set in the provisioning session.
- :return: ``True`` if the new `ConsumptionReportingConfiguration` was successfully set in the provisioning session or
- ``False`` if the operation failed (e.g. because there was already a `ConsumptionReportingConfiguration` set).
- '''
- if provisioning_session not in self.__provisioning_sessions:
- return False
- await self.__connect()
- crc_resp: Union[bool,ConsumptionReportingConfigurationResponse,None] = \
- await self.__m1_client.activateConsumptionReportingConfiguration(provisioning_session, crc)
- if isinstance(crc_resp,bool):
- return crc_resp
- ps = await self.__getProvisioningSessionCache(provisioning_session)
- if ps is not None:
- ps['consumption-reporting-configuration'] = {k.lower(): v for k,v in crc_resp.items()}
- return True
-
- async def consumptionReportingConfigurationGet(self, provisioning_session: ResourceId) -> Optional[ConsumptionReportingConfiguration]:
- '''Retrieve the `ConsumptionReportingConfiguration` set on a provisioning session
-
- :param provisioning_session: The provisioning session id to retrieve the `ConsumptionReportingConfiguration` for.
-
- :return: a `ConsumptionReportingConfiguration` for the provisioning session or ``None`` if the provisioning session does not
- exist or if it has no `ConsumptionReportingConfiguration` set.
- '''
- if provisioning_session not in self.__provisioning_sessions:
- return None
- await self.__cacheConsumptionReportingConfiguration(provisioning_session)
- ps = await self.__getProvisioningSessionCache(provisioning_session)
- if ps is None or ps['consumption-reporting-configuration'] is None:
- return None
- return ConsumptionReportingConfiguration(ps['consumption-reporting-configuration']['consumptionreportingconfiguration'])
-
- async def consumptionReportingConfigurationUpdate(self, provisioning_session: ResourceId, crc: ConsumptionReportingConfiguration) -> bool:
- '''Update the `ConsumptionReportingConfiguration` for a provisioning session
-
- :param provisioning_session: The provisioning session id of the provisioning session to set the
- `ConsumptionReportingConfiguration` in.
- :param chc: The `ConsumptionReportingConfiguration` to set in the provisioning session.
- :return: ``True`` if the new `ConsumptionReportingConfiguration` was successfully set in the provisioning session or
- ``False`` if the operation failed (e.g. because there was no `ConsumptionReportingConfiguration` set).
- '''
- if provisioning_session not in self.__provisioning_sessions:
- return False
- await self.__connect()
- return await self.__m1_client.updateConsumptionReportingConfiguration(provisioning_session, crc)
-
- async def consumptionReportingConfigurationDelete(self, provisioning_session: ResourceId) -> bool:
- '''Remove the `ConsumptionReportingConfiguration` for a provisioning session
-
- :param provisioning_session: The provisioning session id of the provisioning session to remove the
- `ConsumptionReportingConfiguration` in.
-
- :return: ``True`` if the `ConsumptionReportingConfiguration` was successfully removed or ``False`` if the operation failed.
- '''
- if provisioning_session not in self.__provisioning_sessions:
- return False
- await self.__connect()
- return await self.__m1_client.destroyConsumptionReportingConfiguration(provisioning_session)
-
- # PolicyTemplate methods
-
- async def policyTemplateIds(self, provisioning_session_id: ResourceId) -> Optional[List[ResourceId]]:
- '''Get a list of policy template Ids
-
- :param provisioning_session_id: The provisioning session id to retrieve policy template ids for.
- :return: a list of policy template 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)
- ps = self.__provisioning_sessions[provisioning_session_id]['provisioningsession']
- if 'policyTemplateIds' not in ps:
- return []
- return ps['policyTemplateIds']
-
- async def policyTemplateCreate(self, provisioning_session_id: ResourceId, policy_template: PolicyTemplate) -> Optional[ResourceId]:
- '''Create a new policy template
-
- This creates a new policy template in the provisioning session and returns the new policy template id.
-
- :param provisioning_session_id: The provisioning session to create the new policy template in.
- :param policy_template: The policy template to create.
-
- :return: the policy template id of the new policy template 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()
- pol_resp: Optional[PolicyTemplateResponse] = await self.__m1_client.createPolicyTemplate(provisioning_session_id, policy_template)
- if pol_resp is None:
- return None
- pol_id = pol_resp['PolicyTemplate']['policyTemplateId']
- ps = await self.__getProvisioningSessionCache(provisioning_session_id)
- if ps is not None:
- if 'policyTemplates' not in ps or ps['policyTemplates'] is None:
- # create policy template cache
- ps['policyTemplates'] = {pol_id: {k.lower(): v for k,v in pol_resp.items()}}
- elif pol_id not in ps['policyTemplates'] or ps['policyTemplates'][pol_id] is None:
- # Store new policy template info
- ps['policyTemplates'][pol_id] = {k.lower(): v for k,v in pol_resp.items()}
- else:
- # Update the policy template info
- if pol_resp['PolicyTemplate'] is None:
- pol_resp['PolicyTemplate'] = ps['policyTemplates'][pol_id]['policytemplate']
- ps['policyTemplates'][pol_id] = {k.lower(): v for k,v in pol_resp.items()}
-
- return pol_id
-
- async def policyTemplateGet(self, provisioning_session_id: ResourceId, policy_template_id: ResourceId) -> Optional[PolicyTemplate]:
- '''Retrieve a policy template
-
- '''
- if provisioning_session_id not in self.__provisioning_sessions:
- return None
- await self.__cachePolicyTemplates(provisioning_session_id)
- ps = self.__provisioning_sessions[provisioning_session_id]
- if ps is None or 'policyTemplates' not in ps or ps['policyTemplates'] is None or policy_template_id not in ps['policyTemplates']:
- return None
- return PolicyTemplate(ps['policyTemplates'][policy_template_id]['policytemplate'])
-
- async def policyTemplateUpdate(self, provisioning_session_id: ResourceId, policy_template_id: ResourceId, policy_template: PolicyTemplate) -> Optional[bool]:
- '''Update a policy template
-
- '''
- if provisioning_session_id not in self.__provisioning_sessions:
- return False
- await self.__connect()
- return await self.__m1_client.updatePolicyTemplate(provisioning_session_id, policy_template_id, policy_template)
-
- async def policyTemplateDelete(self, provisioning_session_id: ResourceId, policy_template_id: ResourceId) -> bool:
- '''Delete a policy template
-
- '''
- if provisioning_session_id not in self.__provisioning_sessions:
- return False
- await self.__connect()
- return await self.__m1_client.destroyPolicyTemplate(provisioning_session_id, policy_template_id)
-
- # Convenience methods
-
- 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, extra_domain_names: Optional[List[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 *extra_domain_names* is given, is not
- ``None`` and contains at least one entry 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 extra_domain_names: An optional list of domain names to add as extra SubjectAltName entries.
- :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 extra_domain_names is not None and isinstance(extra_domain_names, bytes):
- extra_domain_names = extra_domain_names.decode('utf-8')
- if extra_domain_names is not None and isinstance(extra_domain_names, str):
- if len(extra_domain_names) > 0:
- extra_domain_names = [extra_domain_names]
- else:
- extra_domain_names = None
- if extra_domain_names is not None and len(extra_domain_names) == 0:
- extra_domain_names = None
- if extra_domain_names 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,extra_domain_names=extra_domain_names)
- if csr is None:
- return None
- cert_id = csr[0]
- csr_pem = csr[1]
- cert_signer = await self.__getCertificateSigner()
- cert: Optional[str] = await cert_signer.signCertificate(csr_pem)
- if cert is None:
- self.__log.error('Failed to generate certificate with domainNameAlias')
- return None
- # 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: str, app_id: ApplicationId, entrypoints: Optional[List[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 entrypoints: Optional list of ``distributionConfiguration.entryPoint.relativePath`` 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.
- '''
- self.__log.debug(f'createNewDownlinkPullStream(ingesturl={ingesturl!r}, app_id={app_id!r}, entrypoints={entrypoints!r}, name={name!r}, asp_id={asp_id!r}, ssl={ssl!r}, insecure={insecure!r}, domain_name_alias={domain_name_alias!r})')
- # 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:
- raise RuntimeError('Failed to create a provisioning session')
- # Create an SSL certificate if requested
- if ssl:
- cert: Optional[ResourceId] = await self.createNewCertificate(provisioning_session, extra_domaqin_names=[domain_name_alias])
- 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 entrypoints is None or len(entrypoints) == 0:
- entrypoints = [None]
- for ep in entrypoints:
- if ssl and cert is not None:
- dc = {'certificateId': cert}
- if domain_name_alias is not None:
- dc['domainNameAlias'] = domain_name_alias
- if ep is not None:
- dc['entryPoint'] = {'relativePath': ep, 'contentType': await self.__pathToContentType(ep)}
- chc['distributionConfigurations'] += [dc]
- if insecure:
- dc = {}
- if domain_name_alias is not None:
- dc['domainNameAlias'] = domain_name_alias
- if ep is not None:
- dc['entryPoint'] = {'relativePath': ep, 'contentType': await self.__pathToContentType(ep)}
- chc['distributionConfigurations'] += [dc]
- if not await self.contentHostingConfigurationCreate(provisioning_session, chc):
- raise RuntimeError('Failed to create the content hosting configuration')
- return provisioning_session
-
- async def setOrUpdateConsumptionReporting(self, provisioning_session: ResourceId, crc: ConsumptionReportingConfiguration) -> bool:
- '''Set or update the consumption reporting parameters for a provisioning session
-
- :param ResourceId provisioning_session: The provisioning session to set the consumption report on.
- :param ConsumptionReportingConfiguration crc: The ConsumptionReportingConfiguration to set.
-
- :return: ``True`` if the configuration was set or ``False`` if the setting failed.
- '''
- if provisioning_session not in self.__provisioning_sessions:
- return False
- await self.__cacheConsumptionReportingConfiguration(provisioning_session)
- ps = await self.__getProvisioningSessionCache(provisioning_session)
- if ps is None or ps['consumption-reporting-configuration'] is None:
- return await self.consumptionReportingConfigurationCreate(provisioning_session, crc)
- return await self.consumptionReportingConfigurationUpdate(provisioning_session, crc)
-
- # Private data
-
- __file_suffix_to_mime = {
- 'mpd': 'application/dash+xml',
- 'm3u8': 'application/vnd.apple.mpegurl',
- }
-
- __regex_to_mime = [
- (re.compile(r'mpd'), 'application/dash+xml'),
- (re.compile(r'm3u8'), 'application/vnd.apple.mpegurl'),
- (re.compile(r'dash', re.IGNORECASE), 'application/dash+xml'),
- (re.compile(r'hls', re.IGNORECASE), 'application/vnd.apple.mpegurl'),
- ]
-
- # Private methods
-
- async def __pathToContentType(self, path: str) -> str:
- self.__log.debug(f'__pathToContentType({path!r})')
- type_map = {
- 'mpd': 'application/dash+xml',
- 'm3u8': 'application/vnd.apple.mpegurl',
- }
- suffix = path.rsplit('.',1)[-1]
- if suffix in self.__file_suffix_to_mime:
- return self.__file_suffix_to_mime[suffix]
- for regexp, ctype in self.__regex_to_mime:
- if regexp.search(path) is not None:
- return ctype
- return 'application/octet-stream'
-
- 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
-
- 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()
- to_remove = []
- for prov_sess in sessions:
- if await self.__m1_client.getProvisioningSessionById(prov_sess) is None:
- to_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]:
- '''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) -> 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) -> 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:
- await self.__connect()
- result = await self.__m1_client.getProvisioningSessionById(prov_sess)
- if result is not None:
- 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,
- 'consumption-reporting-configuration': None,
- 'certificates': None,
- 'policyTemplates': None,
- })
- # initialise ServerCertificates cache with the available IDs
- if 'serverCertificateIds' in ps['provisioningsession']:
- ps['certificates'] = {k: None for k in ps['provisioningsession']['serverCertificateIds']}
- # initialise PolicyTemplate cache with the available IDs
- if 'policyTemplateIds' in ps['provisioningsession']:
- ps['policyTemplates'] = {k: None for k in ps['provisioningsession']['policyTemplateIds']}
-
- 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)
- 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.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):
- '''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)
- 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) -> 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)
- 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:
- 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 __cacheConsumptionReportingConfiguration(self, provisioning_session_id: ResourceId) -> None:
- '''Cache the `ConsumptionReportingConfiguration` 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 `ConsumptionReportingConfiguration` for.
- '''
- await self.__cacheProvisioningSession(provisioning_session_id)
- ps = self.__provisioning_sessions[provisioning_session_id]
- now = datetime.datetime.now(datetime.timezone.utc)
- crc = ps['consumption-reporting-configuration']
- if crc is None or crc['cache-until'] is None or crc['cache-until'] < now:
- await self.__connect()
- result: Optional[ConsumptionReportingConfigurationResponse] = \
- await self.__m1_client.retrieveConsumptionReportingConfiguration(provisioning_session_id)
- if result is not None:
- if crc is None:
- crc = {}
- ps['consumption-reporting-configuration'] = crc
- crc.update({k.lower(): v for k,v in result.items()})
- else:
- ps['consumption-reporting-configuration'] = None
-
- async def __cachePolicyTemplates(self, provisioning_session_id: ResourceId):
- '''Cache all policy templates 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 policy templates for.
- '''
- await self.__cacheProvisioningSession(provisioning_session_id)
- ps = self.__provisioning_sessions[provisioning_session_id]
- now = datetime.datetime.now(datetime.timezone.utc)
- if ps is None or 'policyTemplates' not in ps or ps['policyTemplates'] is None:
- return
- ret_err = None
- for pol_id,pol in list(ps['policyTemplates'].items()):
- if pol is None:
- pol = {'etag': None, 'last-modified': None, 'cache-until': None, 'policytemplate': None}
- ps['policyTemplates'][pol_id] = pol
- if pol['cache-until'] is None or pol['cache-until'] < now:
- await self.__connect()
- try:
- result = await self.__m1_client.retrievePolicyTemplate(provisioning_session_id, pol_id)
- if result is not None:
- pol.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 __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`.
- '''
- signer_args = {}
- if self.__cert_signer is None:
- self.__cert_signer = 'rt_m1_client.certificates.DefaultCertificateSigner'
- if isinstance(self.__cert_signer, str):
- if '(' in self.__cert_signer:
- self.__cert_signer, args_str = self.__cert_signer.split('(',1)
- args_str = args_str[:-1]
- signer_args = dict([tuple([p.strip() for p in kv.split('=')]) for kv in args_str.split(',')])
- 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)
- try:
- if inspect.isclass(self.__cert_signer) and issubclass(self.__cert_signer, CertificateSigner):
- self.__cert_signer = await self.__cert_signer(data_store=self.__data_store_dir, **signer_args)
- except TypeError:
- pass
- if inspect.iscoroutinefunction(self.__cert_signer):
- self.__cert_signer = await self.__cert_signer(data_store=self.__data_store_dir, **signer_args)
- 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) -> None:
- '''Connect to the M1Client
-
- :meta private:
- '''
- if self.__m1_client is None:
- self.__m1_client = M1Client(self.__m1_host)
-
- def _dump_state(self) -> None:
- '''Dump the current provisioning session cache to the log
- '''
- self.__log.debug(repr(self.__provisioning_sessions))
-
-__all__ = [
- # Classes
- 'M1Session',
- ]
diff --git a/tools/python3/lib/rt_m1_client/types.py b/tools/python3/lib/rt_m1_client/types.py
deleted file mode 100644
index 5f9f917..0000000
--- a/tools/python3/lib/rt_m1_client/types.py
+++ /dev/null
@@ -1,1076 +0,0 @@
-#!/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
-import string
-from typing import List, Literal, TypedDict, Union
-
-def wrapped_default(self, obj):
- return getattr(obj.__class__, "__jsontype__", wrapped_default.default)(obj)
-wrapped_default.default = json.JSONEncoder().default
-
-json.JSONEncoder.default = wrapped_default
-
-# TS 26.512 ProvisioningSession
-
-ApplicationId = str
-ResourceId = str
-Uri = str
-ProvisioningSessionId = ResourceId
-ProvisioningSessionType = Literal['DOWNLINK','UPLINK']
-
-class ProvisioningSessionMandatory(TypedDict):
- '''Mandatory fields for a `ProvisioningSession` v17.7.0
- '''
- provisioningSessionId: ProvisioningSessionId
- provisioningSessionType: ProvisioningSessionType
- appId: 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:
- 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__)}: {json_str}')
-
- return ProvisioningSession(ret)
-
-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 #: A regex to match the request path.
- mappedPath: str #: The path to map in instead of the matched path.
-
-class CachingDirectiveMandatory(TypedDict):
- '''Mandatory fields from CachingConfiguration.cachingDirectives structure in TS 26.512
- '''
- noCache: bool #: ``True`` if ``no-cache`` should be included for this directive.
-
-class CachingDirective(CachingDirectiveMandatory, total=False):
- '''CachingConfiguration.cachingDirectives structure in TS 26.512
- '''
- 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 #: A URL pattern to match for the cache configuration
-
-class CachingConfiguration(CachingConfigurationMandatory, total=False):
- '''CachingConfiguration structure in TS 26.512
- '''
- cachingDirectives: List[CachingDirective] #: Array of cache directives for the matched URL
-
-class ContentProtocolDescriptorMandatory(TypedDict):
- '''Mandatory fields from ContentProtocolDescriptor in TS 26.512
- '''
- termIdentifier: Uri #: A URI (usually URN) to identify an ingest protocol.
-
-class ContentProtocolDescriptor(ContentProtocolDescriptorMandatory, total=False):
- '''ContentProtocolDescriptor structure in TS 26.512
- '''
- descriptionLocator: Uri #: A URL to documentation describing the *termIdentfier*.
-
-class ContentProtocols(TypedDict, total=False):
- '''ContentProtocols structure in TS 26.512
- '''
- 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(json_str))
-
-class DistributionNetworkType(enum.Enum):
- '''Enumeration DistributionNetworkType in TS 26.512
- '''
- NETWORK_EMBMS = enum.auto() #: Distribution type is via EMBMS network.
-
- def __jsontype__(self, **options):
- return 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() #: Distribution mode is exclusive
- MODE_HYBRID = enum.auto() #: Distribution mode is hybrid
- MODE_DYNAMIC = enum.auto() #: Distribution mode is dynamic
-
- def __jsontype__(self, **options):
- return str(self)
-
- def __str__(self):
- '''String representation of the `DistributionMode`.
-
- :return: a `str` containing the name of the enumerated `DistributionMode`.
- '''
- return self.name
-
-class M1MediaEntryPointMandatory(TypedDict, total=True):
- '''Mandatory fields from M1MediaEntryPoint in TS 26.512 (v17.5.0)
- '''
- relativePath: str
- contentType: str
-
-class M1MediaEntryPoint(M1MediaEntryPointMandatory, total=False):
- '''M1MediaEntryPoint in TS 26.512 (v17.5.0)
- '''
- profiles: List[str]
-
-class DistributionConfiguration(TypedDict, total=False):
- '''
- DistributionConfiguration structure in TS 26.512
- '''
- contentPreparationTemplateId: ResourceId
- canonicalDomainName: str
- domainNameAlias: str
- baseURL: Uri
- entryPoint: M1MediaEntryPoint
- 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,
- })]
-
- @staticmethod
- def format(dc: "DistributionConfiguration", indent: int = 0) -> str:
- prefix = ' ' * indent
- s = f"{prefix}- URL: {dc['baseURL']}"
- if 'canonicalDomainName' in dc:
- s += f'''
-{prefix} Canonical Domain Name: {dc['canonicalDomainName']}'''
- if 'contentPreparationTemplateId' in dc:
- s += f'''
-{prefix} Content Preparation Template: {dc['contentPreparationTemplateId']}'''
- if 'certificateId' in dc:
- s += f'''
-{prefix} Certificate: {dc['certificateId']}'''
- if 'domainNameAlias' in dc:
- s += f'''
-{prefix} Domain Name Alias: {dc['domainNameAlias']}'''
- if 'entryPoint' in dc:
- s += f'''
-{prefix} Entry point:
-{prefix} Relative Path: {dc['entryPoint']['relativePath']}
-{prefix} Content Type: {dc['entryPoint']['contentType']}'''
- if 'profiles' in dc['entryPoint']:
- s += f'''
-{prefix} Profiles:'''
- for p in dc['entryPoint']['profiles']:
- s += f'''
-{prefix} - {p}'''
- if 'pathRewriteRules' in dc:
- s += f'''
-{prefix} Path Rewrite Rules:'''
- for prr in dc['pathRewriteRules']:
- s += f'''
-{prefix} - {prr['requestPathPattern']} => {prr['mappedPath']}'''
- if 'cachingConfigurations' in dc:
- s += f'''
-{prefix} Caching Configurations:'''
- for cc in dc['cachingConfigurations']:
- s += f'''
-{prefix} - URL Pattern: {cc['urlPatternFilter']}'''
- if 'cachingDirectives' in cc:
- cd = cc['cachingDirectives']
- s += f'''
-{prefix} Directive:
-{prefix} no-cache={repr(cd['noCache'])}'''
- if 'maxAge' in cd:
- s += f'''
-{prefix} max-age={cd['maxAge']}'''
- if 'statusCodeFilters' in cd:
- s += f'''
-{prefix} filters=[{', '.join([str(i) for i in cd['statusCodeFilters']])}]'''
- if 'geoFencing' in dc:
- gf = dc['geoFencing']
- s += f'''
-{prefix} Geo-fencing({gf['locatorType']}):'''
- for l in gf['locators']:
- s += f'''
-{prefix} - {l}'''
- if 'urlSignature' in dc:
- us = dc['urlSignature']
- s += f'''
-{prefix} URL Signature:
-{prefix} - Pattern: {us['urlPattern']}
-{prefix} Token: {us['tokenName']}
-{prefix} Passphase name: {us['passphraseName']}
-{prefix} Passphase: {us['passphrase']}
-{prefix} Token Expiry name: {us['tokenExpiryName']}
-{prefix} Use IP Address?: {us['useIPAddress']!r}'''
- if 'ipAddressName' in us:
- s += f'''
-{prefix} IP Address name: {us['ipAddressName']}'''
- return s
-
-class IngestConfiguration(TypedDict, total=False):
- '''
- IngestConfiguration structure from TS 26.512
- '''
- pull: bool
- protocol: Uri
- baseURL: Uri
-
- @staticmethod
- def format(ic: "IngestConfiguration", indent: int = 0) -> str:
- prefix = ' ' * indent
- return f'''{prefix}Type: {ic['protocol']}
-{prefix}Pull Ingest?: {ic['pull']!r}
-{prefix}URL: {ic['baseURL']}'''
-
-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
- '''
-
- @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)
-
- @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']}
-Ingest:
-{IngestConfiguration.format(chc['ingestConfiguration'], 2)}
-Distributions:
-{cls.__formatDistributions(chc)}
-'''
-
- @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.
- '''
- return '\n'.join([DistributionConfiguration.format(d, indent) for d in chc['distributionConfigurations']])
-
-# TS 26.512 ConsumptionReportingConfiguration
-
-class ConsumptionReportingConfiguration(TypedDict, total=False):
- '''
- ConsumptionReportingConfiguration structure from TS 26.512
- '''
- reportingInterval: int
- samplePercentage: float
- locationReporting: bool
- accessReporting: bool
-
- @staticmethod
- def fromJSON(crc_json: str) -> "ConsumptionReportingConfiguration":
- '''Create a ConsumptionReportingConfiguration from a JSON string
-
- :param str json: The JSON string to parse into a ConsumptionReportingConfiguration structure.
-
- :return: The `ConsumptionReportingConfiguration` generated from the JSON string.
-
- :raise ValueError: If the JSON could not be parsed.
- '''
- # parse the JSON
- crc = json.loads(crc_json)
- # validate types
- if 'reportingInterval' in crc:
- if not isinstance(crc['reportingInterval'], int):
- raise ValueError('ConsumptionReportingConfiguration.reportingInterval must be an integer')
- if crc['reportingInterval'] <= 0:
- raise ValueError('ConsumptionReportingConfiguration.reportingInterval must be an integer greater than 0')
- if 'samplePercentage' in crc:
- if isinstance(crc['samplePercentage'], int):
- crc['samplePercentage'] = float(crc['samplePercentage'])
- if not isinstance(crc['samplePercentage'], float):
- raise ValueError('ConsumptionReportingConfiguration.samplePercentage must be an integer or floating point number')
- if crc['samplePercentage'] < 0.0 or crc['samplePercentage'] > 100.0:
- raise ValueError('ConsumptionReportingConfiguration.samplePercentage must be between 0.0 and 100.0 inclusive')
- if 'locationReporting' in crc:
- if not isinstance(crc['locationReporting'], bool):
- raise ValueError('ConsumptionReportingConfiguration.locationReporting must be a boolean')
- if 'accessReporting' in crc:
- if not isinstance(crc['accessReporting'], bool):
- raise ValueError('ConsumptionReportingConfiguration.accessReporting must be a boolean')
- # Validate against ContentHostingConfiguration type
- return ConsumptionReportingConfiguration(crc)
-
- @classmethod
- def format(cls, crc: "ConsumptionReportingConfiguration", indent: int = 0) -> str:
- prefix: str = ' ' * indent
- ret: str = ''
- if 'reportingInterval' in crc:
- ret += f"{prefix}Reporting interval: {crc['reportingInterval']}s\n"
- if 'samplePercentage' in crc:
- ret += f"{prefix}Sample percentage: {crc['samplePercentage']}\n"
- if 'locationReporting' in crc and crc['locationReporting']:
- ret += f"{prefix}With location reporting\n"
- if 'accessReporting' in crc and crc['accessReporting']:
- ret += f"{prefix}With access reporting\n"
- if len(ret) == 0:
- ret = f"{prefix}Active with no parameters set\n"
- return ret
-
-# TS 26.512 PolicyTemplate
-class PolicyTemplateState(enum.Enum):
- '''
- PolicyTemplate.state enumeration from TS 26.512
- '''
- PENDING = enum.auto() # pylint: disable=invalid-name
- INVALID = enum.auto() # pylint: disable=invalid-name
- READY = enum.auto() # pylint: disable=invalid-name
- SUSPENDED = enum.auto() # pylint: disable=invalid-name
-
- def __jsontype__(self, **options):
- return str(self)
-
- def __str__(self):
- return self.name
-
-class SnssaiMandatory(TypedDict):
- '''
- Snssai structure mandatory fields from TS 29.571
- '''
- sst: int
-
-class Snssai(SnssaiMandatory, total=False):
- '''
- Snssai structure from TS 29.571
- '''
- sd: str
-
- @staticmethod
- def validate(snssai: "Snssai", json: str) -> bool:
- # check mandatory fields presence
- for mandatory_field in SnssaiMandatory.__required_keys__:
- if mandatory_field not in snssai:
- raise TypeError(f'Snssai must contain a {mandatory_field} field: {json}')
-
- # convert enums
- #asc['?'] = ???(asc['?'])
-
- # validate substructures
- if not isinstance(snssai['sst'], int):
- raise ValueError(f'''Snssai.sst must be an integer''')
- if snssai['sst'] < 0 or snssai['sst'] > 255:
- raise ValueError(f'''Snssai.sst must be an integer between 0 and 255 inclusive: found Snssai.sst = {snssai['sst']}''')
- if 'sd' in snssai:
- if len(snssai['sd']) != 6 or any(c not in string.hexdigits for c in snssai['sd']):
- raise ValueError(f'''Snssai.sd must be a 6 digit hexadecimal string: found Snssai.sd = {snssai['sd']}''')
- return True
-
- @staticmethod
- def format(snssai: "Snssai", indent: int = 0) -> str:
- prefix: str = ' ' * indent
- ret: str = f'''{prefix}Sst: {snssai['sst']}'''
- if 'sd' in snssai:
- ret += f"\n{prefix}Sd: {snssai['sd']}"
- return ret
-
-class BitRate(object):
- '''
- BitRate string from TS 29.571
- '''
- def __init__(self, *args, **kwargs):
- if len(args) == 1 and len(kwargs) == 0:
- if isinstance(args[0], bytes):
- args[0] = args[0].decode('utf-8')
- if isinstance(args[0], str):
- self.__bitrate = self.__parseBitrateString(args[0])
- elif isinstance(args[0], int):
- self.__bitrate = float(args[0])
- elif isinstance(args[0], float):
- self.__bitrate = args[0]
- elif isinstance(args[0], BitRate):
- self.__bitrate = args[0].bitrate()
- else:
- raise TypeError(f'BitRate initialiser must be str, int or float: given {type(args[0]).__name__}')
- elif len(args) == 0 and len(kwargs) == 1 and kwargs.keys()[0] in ['bps', 'kbps', 'mbps', 'gbps', 'tbps', 'pbps']:
- k,v = kwargs.items()[0]
- if k == 'bps':
- self.__bitrate = float(v)
- elif k == 'kbps':
- self.__bitrate = v*1000.0
- elif k == 'mbps':
- self.__bitrate = v*1000000.0
- elif k == 'gbps':
- self.__bitrate = v*1000000000.0
- elif k == 'tbps':
- self.__bitrate = v*1000000000000.0
- else: # 'pbps'
- self.__bitrate = v*1000000000000000.0
- else:
- raise ValueError('Only a bitrate string or one of the bitrate keywords can be used to initialise a BitRate')
-
- def bitrate(self):
- return self.__bitrate
-
- def __repr__(self) -> str:
- if self.__bitrate < 1000:
- return f'BitRate(bps={self.__bitrate})'
- if self.__bitrate < 1000000:
- return f'BitRate(kbps={self.__bitrate/1000.0})'
- if self.__bitrate < 1000000000:
- return f'BitRate(mbps={self.__bitrate/1000000.0})'
- if self.__bitrate < 1000000000000:
- return f'BitRate(gbps={self.__bitrate/1000000000.0})'
- if self.__bitrate < 1000000000000000:
- return f'BitRate(tbps={self.__bitrate/1000000000000.0})'
- return f'BitRate(pbps={self.__bitrate/1000000000000000.0})'
-
- def __str__(self) -> str:
- if self.__bitrate < 1000:
- return f'{self.__bitrate} bps'
- if self.__bitrate < 1000000:
- return f'{self.__bitrate/1000.0:.3f} Kbps'
- if self.__bitrate < 1000000000:
- return f'{self.__bitrate/1000000.0:.3f} Mbps'
- if self.__bitrate < 1000000000000:
- return f'{self.__bitrate/1000000000.0:.3f} Gbps'
- if self.__bitrate < 1000000000000000:
- return f'{self.__bitrate/1000000000000.0:.3f} Tbps'
- return f'{self.__bitrate/1000000000000000.0:.3f} Pbps'
-
- def __jsontype__(self, **options):
- return str(self)
-
- def __lt__(self, other: Union[int,float,"BitRate"]) -> bool:
- if isinstance(other, int) or isinstance(other, float):
- return self.__bitrate < other
- if isinstance(other, BitRate):
- return other > self.__bitrate
- raise TypeError('Can only compare a BitRate to another BitRate, int or float')
-
- def __gt__(self, other: Union[int,float,"BitRate"]) -> bool:
- if isinstance(other, int) or isinstance(other, float):
- return self.__bitrate > other
- if isinstance(other, BitRate):
- return other < self.__bitrate
- raise TypeError('Can only compare a BitRate to another BitRate, int or float')
-
- def __eq__(self, other: Union[int,float,"BitRate"]) -> bool:
- if isinstance(other, int) or isinstance(other, float):
- return self.__bitrate == other
- if isinstance(other, BitRate):
- return other == self.__bitrate
- raise TypeError('Can only compare a BitRate to another BitRate, int or float')
-
- def __le__(self, other: Union[int,float,"BitRate"]) -> bool:
- return not self > other
-
- def __ge__(self, other: Union[int,float,"BitRate"]) -> bool:
- return not self < other
-
- def __ne__(self, other: Union[int,float,"BitRate"]) -> bool:
- return not self == other
-
- @staticmethod
- def __parseBitrateString(br: str) -> float:
- val,units = (br.split(' ',1) + [None])[:2]
- val = float(val)
- if units not in ['bps', 'Kbps', 'Mbps', 'Gbps', 'Tbps', 'Pbps']:
- raise ValueError('BitRate string must have units of bps, Kbps, Mbps, Gbps, Tbps or Pbps')
- if units == 'bps':
- return val
- if units == 'Kbps':
- return val*1000.0
- if units == 'Mbps':
- return val*1000000.0
- if units == 'Gbps':
- return val*1000000000.0
- if units == 'Tbps':
- return val*1000000000000.0
- return val*1000000000000000.0
-
-class AppSessionContext(TypedDict, total=False):
- '''
- PolicyTemplate.applicationSessionContext structure in TS 26.512
- '''
- sliceInfo: Snssai
- dnn: str
-
- @staticmethod
- def fromJSON(asc_json: str) -> "AppSessionContext":
- '''Create an AppSessionContext from a JSON string
-
- :param str json: The JSON string to parse into a AppSessionContext structure.
-
- :return: The `AppSessionContext` generated from the JSON string.
-
- :raise TypeError: If the AppSessionContext is missing mandatory fields.
- :raise ValueError: If the JSON could not be parsed.
- '''
- # parse the JSON
- asc = json.loads(asc_json)
- AppSessionContext.validate(asc, asc_json)
- return AppSessionContext(asc)
-
- @staticmethod
- def validate(asc: "AppSessionContext", json: str) -> bool:
- # check mandatory fields presence
- #for mandatory_field in AppSessionContextMandatory.__required_keys__:
- # if mandatory_field not in pt:
- # raise TypeError(f'AppSessionContext must contain a {mandatory_field} field: {json}')
-
- # convert enums
- #asc['?'] = ???(asc['?'])
-
- # validate substructures
- if 'sliceInfo' in asc:
- Snssai.validate(asc['sliceInfo'], json)
- if 'dnn' in asc:
- if not isinstance(asc['dnn'], str):
- raise ValueError(f'''AppSessionContext.dnn must be a string if present''')
- return True
-
- @classmethod
- def format(cls, asc: "AppSessionContext", indent: int = 0) -> str:
- prefix: str = ' ' * indent
- ret: str = ''
- if 'sliceInfo' in asc:
- ret += f'''{prefix}Slice Info:
-{Snssai.format(asc['sliceInfo'], indent+2)}
-'''
- if 'dnn' in asc:
- ret += f'''{prefix}Network Name: {asc['dnn']}
-'''
- return ret
-
-class M1QoSSpecification(TypedDict, total=False):
- '''
- M1QoSSpecification object from TS 26.512
- '''
- qosReference: str
- maxBtrUl: BitRate
- maxBtrDl: BitRate
- maxAuthBtrUl: BitRate
- maxAuthBtrDl: BitRate
- defPacketLossRateDl: int
- defPacketLossRateUl: int
-
- @staticmethod
- def fromJSON(qs_json: str) -> "M1QoSSpecification":
- '''Create an M1QoSSpecification from a JSON string
-
- :param str qs_json: The JSON string to parse into a M1QoSSpecification structure.
-
- :return: The `M1QoSSpecification` generated from the JSON string.
-
- :raise TypeError: If the M1QoSSpecification is missing mandatory fields.
- :raise ValueError: If the JSON could not be parsed.
- '''
- # parse the JSON
- try:
- qs = json.loads(qs_json)
- except json.JSONDecodeError as err:
- raise ValueError("Unable to parse JSON as M1QoSSpecification")
- M1QoSSpecification.validate(qs, qs_json)
- return M1QoSSpecification(qs)
-
- @staticmethod
- def validate(qs: "M1QoSSpecification", json: str) -> bool:
- # check mandatory fields presence
- #for mandatory_field in AppSessionContextMandatory.__required_keys__:
- # if mandatory_field not in pt:
- # raise TypeError(f'AppSessionContext must contain a {mandatory_field} field: {json}')
-
- # convert enums
- #asc['?'] = ???(asc['?'])
-
- # validate substructures
- for br_field in ['maxBtrUl', 'maxBtrDl', 'maxAuthBtrUl', 'maxAuthBtrDl']:
- if br_field in qs:
- qs[br_field] = BitRate(qs[br_field])
- for lr_field in ['defPacketLossRateDl', 'defPacketLossRateUl']:
- if lr_field in qs:
- if not isinstance(qs[lr_field],int):
- raise ValueError(f'{lr_field} is {type(qs[lr_field])} not an integer')
- if qs[lr_field] < 0:
- raise ValueError(f'{lr_field} must be a positive integer')
- return True
-
- @classmethod
- def format(cls, qs: "M1QoSSpecification", indent: int = 0) -> str:
- prefix: str = ' ' * indent
- ret: str = ''
- if 'qosReference' in qs:
- ret += f'''{prefix}QoS Reference: {qs['qosReference']}
-'''
- if 'maxBtrUl' in qs:
- ret += f'''{prefix}Maximum Uplink Bitrate: {qs['maxBtrUl']}
-'''
- if 'maxBtrDl' in qs:
- ret += f'''{prefix}Maximum Downlink Bitrate: {qs['maxBtrDl']}
-'''
- if 'maxAuthBtrUl' in qs:
- ret += f'''{prefix}Maximum Authorised Uplink Bitrate: {qs['maxAuthBtrUl']}
-'''
- if 'maxAuthBtrDl' in qs:
- ret += f'''{prefix}Maximum Authorised Downlink Bitrate: {qs['maxAuthBtrDl']}
-'''
- if 'defPacketLossRateDl' in qs:
- ret += f'''{prefix}Default Downlink Packet Loss Rate: {qs['defPacketLossRateDl']} packets/s
-'''
- if 'defPacketLossRateUl' in qs:
- ret += f'''{prefix}Default Uplink Packet Loss Rate: {qs['defPacketLossRateUl']} packets/s
-'''
- return ret
-
-class SponsoringStatus(enum.Enum):
- '''
- SponsoringStatus enumeration from TS 29.514
- '''
- SPONSOR_DISABLED = enum.auto() # pylint: disable=invalid-name
- SPONSOR_ENABLED = enum.auto() # pylint: disable=invalid-name
-
- def __jsontype__(self, **options):
- return str(self)
-
- def __str__(self):
- return self.name
-
-class ChargingSpecification(TypedDict, total=False):
- '''
- ChargingSpecification object from TS 26.512
- '''
- sponId: str
- sponStatus: SponsoringStatus
- gpsi: List[str]
-
- @staticmethod
- def fromJSON(cs_json: str) -> "ChargingSpecification":
- '''Create a ChargingSpecification from a JSON string
- '''
- try:
- cs = json.loads(cs_json)
- except json.JSONDecodeError as err:
- raise ValueError(f'Unable to parse JSON from: {cs_json}')
- ChargingSpecification.validate(cs)
- return ChargingSpecification(cs)
-
- @staticmethod
- def validate(cs: dict, json: str) -> bool:
- '''Validate a dict as a ChargingSpecification
- '''
- # convert enums
- if 'sponStatus' in cs:
- cs['sponStatus'] = SponsoringStatus[cs['sponStatus']]
- # check types
- if 'sponId' in cs and not isinstance(cs['sponId'], str):
- raise ValueError(f'Sponsor ID should be a string in ChargingSpecification: {json}')
- if 'gpsi' in cs:
- if not isinstance(cs['gpsi'], list):
- raise ValueError(f'GPSI in ChargingSpecification should be a list when present: {json}')
- for v in cs['gpsi']:
- if not isinstance(v, str):
- raise ValueError(f'GPSI list in ChargingSpecification should only contain strings: {json}')
- return True
-
- @staticmethod
- def format(cs: "ChargingSpecification", indent: int = 0) -> str:
- '''Format a ChargingSpecification as a multiline string
- '''
- prefix: str = ' ' * indent
- nlprefix: str = f"\n{prefix}"
- ret: str = ''
- if 'sponId' in cs:
- ret += f"{nlprefix}Sponsor ID: {cs['sponId']}"
- if 'sponStatus' in cs:
- ret += f"{nlprefix}Sponsor Status: {cs['sponStatus']}"
- if 'gpsi' in cs:
- ret += f"{nlprefix}GPSIs:{nlprefix} {f'{nlprefix} '.join(cs['gpsi'])}"
- return ret[1:]
-
-class PolicyTemplateMandatory(TypedDict):
- '''
- Mandatory fields from PolicyTemplate structure in TS 26.512
- '''
- externalReference: str
-
-class PolicyTemplate(PolicyTemplateMandatory, total=False):
- '''
- PolicyTemplate structure from TS 26.512
- '''
- policyTemplateId: ResourceId
- applicationSessionContext: AppSessionContext
- state: PolicyTemplateState
- stateReason: "ProblemDetail"
- qoSSpecification: M1QoSSpecification
- chargingSpecification: ChargingSpecification
-
- @staticmethod
- def fromJSON(policy_template_json: str) -> "PolicyTemplate":
- '''Create a PolicyTemplate from a JSON string
-
- :param str policy_template_json: The JSON string to parse into a PolicyTemplate structure.
-
- :return: The `PolicyTemplate` generated from the JSON string.
-
- :raise TypeError: If the PolicyTemplate is missing mandatory fields.
- :raise ValueError: If the JSON could not be parsed.
- '''
- # parse the JSON
- pt = json.loads(policy_template_json)
- PolicyTemplate.validate(pt, policy_template_json)
- return PolicyTemplate(pt)
-
- @staticmethod
- def validate(pt: "PolicyTemplate", policy_template_json: str) -> bool:
- # check mandatory fields presence
- for mandatory_field in PolicyTemplateMandatory.__required_keys__:
- if mandatory_field not in pt:
- raise TypeError(f'PolicyTemplate must contain a {mandatory_field} field: {policy_template_json}')
- # convert enums
- if 'state' in pt:
- pt['state'] = PolicyTemplateState[pt['state']]
- #ProblemDetail.validate(pt['stateReason'])
- if 'applicationSessionContext' in pt:
- AppSessionContext.validate(pt['applicationSessionContext'], policy_template_json)
- if 'qoSSpecification' in pt:
- M1QoSSpecification.validate(pt['qoSSpecification'], policy_template_json)
- if 'chargingSpecification' in pt:
- ChargingSpecification.validate(pt['chargingSpecification'], policy_template_json)
- return True
-
- @classmethod
- def format(cls, pt: "PolicyTemplate", indent: int = 0) -> str:
- prefix: str = ' ' * indent
- ret: str = f'''{prefix}PolicyTemplate:
-{prefix} Policy Template Id: {pt['policyTemplateId']}
-{prefix} State: {pt['state']}
-{prefix} State Reason:
-{ProblemDetail.format(pt['stateReason'],indent+4)}
-{prefix} External Reference: {pt['externalReference']}
-'''
- if 'applicationSessionContext' in pt:
- ret += f"{prefix} AppSessionContext:\n{AppSessionContext.format(pt['applicationSessionContext'], indent+4)}"
- if 'qoSSpecification' in pt:
- ret += f"{prefix} QoS Specification:\n{M1QoSSpecification.format(pt['qoSSpecification'], indent+4)}"
- if 'chargingSpecification' in pt:
- ret += f"{prefix} Charging Specification:\n{ChargingSpecification.format(pt['chargingSpecification'], indent+4)}"
- return ret
-
-# 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
-
- @staticmethod
- def format(ip: "InvalidParam", indent: int = 0):
- prefix = ' ' * indent
- ret = f'''{prefix}Parameter: {ip['param']}
-'''
- if 'reason' in ip:
- ret += f"{prefix}Reason: {ip['reason']}\n"
- return ret
-
-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 __jsontype__(self, **options):
- return str(self)
-
- 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
-
- @staticmethod
- def format(ate: "AccessTokenErr", indent: int = 0) -> str:
- prefix = ' ' * indent
- ret = f'''{prefix}Error: {ate['error']}'''
- if 'error_description' in ate:
- ret += f"\n{prefix}Description: {ate['error_description']}"
- if 'error_uri' in ate:
- ret += f"\n{prefix}URI: {ate['error_uri']}"
- return ret
-
-class AccessTokenReqGrantType(enum.Enum):
- '''
- AccessTokenReqGrantType enumeration in TS 29.571
- '''
- client_credentials = enum.auto() # pylint: disable=invalid-name
-
- def __jsontype__(self, **options):
- return str(self)
-
- 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
-
- @staticmethod
- def format(atr: "AccessTokenReq", indent: int = 0) -> str:
- prefix = ' ' * indent
- ret = f'''{prefix}Grant Type: {atr['grant_type']}
-{prefix}NF Instance Id: {atr['nfInstanceId']}
-{prefix}Scope: {atr['scope']}'''
- if 'nfType' in atr:
- ret += f"\n{prefix}NF Type: {atr['nfType']}"
- if 'requesterPlmn' in atr:
- ret += f"\n{prefix}Requester PLMN: {atr['requesterPlmn']}"
- if 'requesterPlmnList' in atr:
- ret += f"\n{prefix}Requester PLMNs: {', '.join(atr['requesterPlmnList'])}"
- if 'requesterSnssaiList' in atr:
- ret += f"\n{prefix}Requester S-NSSAIs: {', '.join(atr['requesterSnssaiList'])}"
- if 'requesterFqdn' in atr:
- ret += f"\n{prefix}Requester FQDN: {atr['requesterFqdn']}"
- if 'requesterSnpnList' in atr:
- ret += f"\n{prefix}Requester SNPNs: {', '.join(atr['requesterSnpnList'])}"
- if 'targetNfType' in atr:
- ret += f"\n{prefix}Target NF Type: {atr['targetNfType']}"
- if 'targetNfInstanceId' in atr:
- ret += f"\n{prefix}Target NF Instance Id: {atr['targetNfInstanceId']}"
- if 'targetPlmn' in atr:
- ret += f"\n{prefix}Target PLMN: {atr['targetPlmn']}"
- if 'targetSnssaiList' in atr:
- ret += f"\n{prefix}Target S-NSSAIs: {', '.join(atr['targetSnssaiList'])}"
- if 'targetNsiList' in atr:
- ret += f"\n{prefix}Target NSIs: {', '.join(atr['targetNsiList'])}"
- if 'targetNfSetId' in atr:
- ret += f"\n{prefix}Target NF Set Id: {atr['targetNfSetId']}"
- if 'targetNfServiceSetId' in atr:
- ret += f"\n{prefix}Target NF Service Set Id: {atr['targetNfServiceSetId']}"
- if 'hnrfAccessTokenUri' in atr:
- ret += f"\n{prefix}HNRF Access Token Uri: {atr['hnrfAccessTokenUri']}"
- if 'sourceNfInstanceId' in atr:
- ret += f"\n{prefix}Souce NF Instance Id: {atr['sourceNfInstanceId']}"
- return ret
-
-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) -> "ProblemDetail":
- '''
- 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'])
- if 'accessTokenRequest' in prob_detail:
- for atr in prob_detail['accessTokenRequest']:
- atr['grant_type'] = AccessTokenReqGrantType(atr['grant_type'])
- return prob_detail
-
- @staticmethod
- def format(pd: "ProblemDetail", indent: int = 0) -> str:
- prefix = ' ' * indent
- ret = ''
- if 'problemtype' in pd:
- ret += f"\n{prefix}Problem Type: {pd['problemtype']}"
- if 'title' in pd:
- ret += f"\n{prefix}Title: {pd['title']}"
- if 'status' in pd:
- ret += f"\n{prefix}Status: {pd['status']}"
- if 'detail' in pd:
- ret += f'''
-{prefix}Detail:
-{prefix} {pd['detail']}'''
- if 'instance' in pd:
- ret += f"\n{prefix}Instance: {pd['instance']}"
- if 'cause' in pd:
- ret += f"\n{prefix}Cause: {pd['cause']}"
- if 'invalidParams' in pd:
- ret += f'''
-{prefix}Invalid Parameters:
-{''.join([InvalidParam.format(p, indent+2) for p in pd['invalidParams']])}'''
- if 'supportedFeatures' in pd:
- ret += f"\n{prefix}Supported Features: {pd['supportedFeatures']}"
- if 'accessTokenError' in pd:
- ret += f'''
-{prefix}Access Token Error:
-{AccessTokenErr.format(pd['accessTokenError'], indent+2)}'''
- if 'accessTokenRequest' in pd:
- ret += f'''
-{prefix}Access Token Request:
-{AccessTokenReq.format(pd['accessTokenRequest'], indent+2)}'''
- if 'nrfId' in pd:
- ret += f"\n{prefix}NRF Id: {pd['nrfId']}"
- return ret[1:]
-
-__all__ = [
- "ProblemDetail",
- "AccessTokenErr",
- "AccessTokenReq",
- "InvalidParam",
- "ApplicationId",
- "ResourceId",
- "PolicyTemplate",
- "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
deleted file mode 100755
index 4f785e2..0000000
--- a/tools/python3/m1_client_cli.py
+++ /dev/null
@@ -1,731 +0,0 @@
-#!/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) 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 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.
-
-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] []
- m1-client consumption create [-h] [-i ] [-p ] [-l] [-a]
- m1-client consumption show [-h]
- m1-client consumption update [-h] [-i ] [-p ] [-l] [-a]
- m1-client consumption delete [-h]
- m1-client policy create [-h]
- m1-client policy show [-h]
- m1-client policy update [-h]
- m1-client policy delete [-h]
-'''
-
-import aiofiles
-import argparse
-import asyncio
-import datetime
-import os.path
-import sys
-from typing import Optional, Union
-
-import cryptography
-import OpenSSL
-
-installed_packages_dir = '@python_packages_dir@'
-if os.path.isdir(installed_packages_dir) and installed_packages_dir not in sys.path:
- sys.path.append(installed_packages_dir)
-
-from rt_m1_client.client import M1Client, ProvisioningSessionResponse, ContentProtocolsResponse, ServerCertificateSigningRequestResponse, ServerCertificateResponse, ContentHostingConfigurationResponse, ConsumptionReportingConfigurationResponse, PolicyTemplateResponse
-from rt_m1_client.types import PROVISIONING_SESSION_TYPE_DOWNLINK, PROVISIONING_SESSION_TYPE_UPLINK, ContentHostingConfiguration, ConsumptionReportingConfiguration, PolicyTemplate
-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 is not None
- fqdns = args.csr
- resp: Optional[ServerCertificateSigningRequestResponse] = await client.createOrReserveServerCertificate(provisioning_session_id, extra_domain_names=fqdns, 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
-
-def format_int_hex_block(v: int, bits: int, bytes_per_line: int, indent: int = 0) -> str:
- digits = int(bits/4)
- h = hex(v)[2:]
- if len(h) < digits:
- zeros = digits - len(h)
- h = '0' * zeros + h
- out_prefix = ' ' * indent
- line_sep = f'\n{out_prefix}'
- line_digits = bytes_per_line*2
- return (out_prefix + line_sep.join([''.join([s[i:i+2]+':' for i in range(0,len(s),2)]) for s in [h[i:i+line_digits] for i in range(0,len(h),line_digits)]]))[:-1]
-
-def format_x509_name(name: OpenSSL.crypto.X509Name, indent: int = 0) -> str:
- '''Return a human readable `str` representing the X509Name
-
- :param pkey: The X509Name for format as a `str`.
- :param indent: The number of space characters to preceed every output line with.
-
- :return: a human readable version of *name*.
- '''
- out_prefix = ' ' * indent
- return out_prefix + ', '.join([k.decode('utf-8')+'='+v.decode('utf-8') for k,v in name.get_components()])
-
-def format_x509_extension(ext: OpenSSL.crypto.X509Extension, indent: int = 0) -> str:
- '''Return a human readable `str` representing the X509Extension
-
- :param pkey: The X509Extension for format as a `str`.
- :param indent: The number of space characters to preceed every output line with.
-
- :return: a human readable version of *ext*.
- '''
- out_prefix = ' ' * indent
- ret = ''
- critical: bool = ext.get_critical()
- value: str = str(ext)
- short_name: str = ext.get_short_name().decode('utf-8')
- name: str = short_name
- long_names = {
- 'subjectAltName': 'X509v3 Subject Alternative Names',
- 'basicConstraints': 'X509v3 Basic Constraints',
- 'authorityKeyIdentifier': 'X509v3 Authority Key Identifier',
- 'subjectKeyIdentifier': 'X509v3 Subject Key Identifier',
- 'authorityInformationAccess': 'Authority Information Access',
- 'extendedKeyUsage': 'X509v3 Extended Key Usage',
- 'crlDistributionPoints': 'X509v3 CRL Distribution Points',
- 'keyUsage': 'X509v3 Key Usage',
- }
- if short_name in long_names:
- name = long_names[short_name]
- ret += out_prefix+name+':'
- if critical:
- ret += ' critical'
- ret += '\n'
- ret += '\n'.join([out_prefix+' '+s for s in value.split('\n')])+'\n'
- return ret
-
-def format_rsa_public_key(key: cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey, indent: int = 0) -> str:
- out_prefix = ' ' * indent
- numbers = key.public_numbers()
- ret = f'''{out_prefix}RSA Public Key: ({key.key_size} bits)
-{out_prefix} Exponent: {numbers.e} ({hex(numbers.e)})
-{out_prefix} Modulus:
-{format_int_hex_block(numbers.n, key.key_size, 15, indent+8)}'''
- return ret
-
-def format_dsa_public_key(key: cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey, indent: int = 0) -> str:
- out_prefix = ' ' * indent
- numbers = key.public_numbers()
- ret = f'''{out_prefix}DSA Public Key: ({key.key_size} bits)
-{out_prefix} Parameters:
-{out_prefix} p: {numbers.parameter_numbers.p}
-{out_prefix} q: {numbers.parameter_numbers.q}
-{out_prefix} g: {numbers.parameter_numbers.g}
-{out_prefix} y:
-{format_int_hex_block(numbers.y, key.key_size, 15, indent=indent+8)}'''
- return ret
-
-def format_dh_public_key(key: cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey, indent: int = 0) -> str:
- out_prefix = ' ' * indent
- numbers = key.public_numbers()
- ret = f'''{out_prefix}Diffie-Hellman Public Key: ({key.key_size} bits)
-{out_prefix} Parameters:
-{out_prefix} p: {numbers.parameter_numbers.p}
-{out_prefix} g: {numbers.parameter_numbers.g}
-{out_prefix} q: {numbers.parameter_numbers.q}
-{out_prefix} y:
-{format_int_hex_block(numbers.y, key.key_size, 15, indent=indent+8)}'''
- return ret
-
-def format_ec_public_key(key: cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey, indent: int = 0) -> str:
- out_prefix = ' ' * indent
- numbers = key.public_numbers()
- ret = f'''{out_prefix}Elliptic-Curve Public Key: ({key.key_size} bits)
-{out_prefix} Curve: {numbers.curve.name}
-{out_prefix} x:
-{format_int_hex_block(numbers.x, key.key_size, 15, indent=indent+8)}
-{out_prefix} y:
-{format_int_hex_block(numbers.y, key.key_size, 15, indent=indent+8)}'''
- return ret
-
-def format_pkey(pkey: OpenSSL.crypto.PKey, indent: int = 0) -> str:
- '''Return a human readable `str` representing the PKey
-
- :param pkey: The PKey for format as a `str`.
- :param indent: The number of space characters to preceed every output line with.
-
- :return: a human readable version of *pkey*.
- '''
- cryptokey = pkey.to_cryptography_key()
- if isinstance(cryptokey, cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey):
- return format_rsa_public_key(cryptokey, indent)
- if isinstance(cryptokey, cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey):
- return format_dsa_public_key(cryptokey, indent)
- if isinstance(cryptokey, cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey):
- return format_dh_public_key(cryptokey, indent)
- if isinstance(cryptokey, cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey):
- return format_ec_public_key(cryptokey, indent)
- out_prefix = ' ' * indent
- ret = f'{out_prefix}{cryptokey.__class__.__name__} type public key, unable to format'
- return ret
-
-def format_x509_pem(pem: str, indent: int = 0) -> str:
- '''Return a human readable `str` representing the X509 public certificate
-
- :param pem: The PEM data for the public certificate.
- :return: the PEM data in human readable form.
- '''
- x509: OpenSSL.crypto.X509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, pem)
- serial: int = x509.get_serial_number()
- subject: OpenSSL.crypto.X509Name = x509.get_subject()
- issuer: OpenSSL.crypto.X509Name = x509.get_issuer()
- start_str: Optional[bytes] = x509.get_notBefore()
- start: Optional[datetime.datetime] = None
- if start_str is not None:
- start = datetime.datetime.strptime(start_str.decode('utf-8'), '%Y%m%d%H%M%SZ').replace(tzinfo=datetime.timezone.utc)
- end_str: Optional[bytes] = x509.get_notAfter()
- end: Optional[datetime.datetime] = None
- if end_str is not None:
- end = datetime.datetime.strptime(end_str.decode('utf-8'), '%Y%m%d%H%M%SZ').replace(tzinfo=datetime.timezone.utc)
- public_key: OpenSSL.crypto.PKey = x509.get_pubkey()
- sig_alg: str = x509.get_signature_algorithm().decode('utf-8')
- version: int = x509.get_version()
- out_prefix = ' ' * indent
- ret: str = f'''{out_prefix}Certificate:
-{out_prefix} Data:
-{out_prefix} Version: {1+version} ({hex(version)})
-{out_prefix} Serial Number: {serial} ({hex(serial)})
-{out_prefix} Signature Algorithm: {sig_alg}
-{out_prefix} Issuer: {format_x509_name(issuer)}
-'''
- if start is not None or end is not None:
- ret += f'{out_prefix} Validity\n'
- if start is not None:
- ret += f'{out_prefix} Not Before: {start:%b %d %H:%M:%S %Y %Z}\n'
- if end is not None:
- ret += f'{out_prefix} Not After: {end:%b %d %H:%M:%S %Y %Z}\n'
- ret += f'{out_prefix} Subject: {format_x509_name(subject)}\n'
- ret += f'''{out_prefix} Subject Public Key Info:
-{format_pkey(public_key, indent=indent+12)}
-'''
- if x509.get_extension_count() > 0:
- ret += f'{out_prefix} X509v3 extensions:\n'
- for ext_idx in range(x509.get_extension_count()):
- ext = x509.get_extension(ext_idx)
- ret += f'{format_x509_extension(ext, indent=indent+12)}'
- return ret
-
-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']}
-{format_x509_pem(resp['ServerCertificate'])}
-''')
- else:
- print(resp['ServerCertificate'])
- return 0
-
-async def cmd_certificates_delete(args: argparse.Namespace) -> int:
- client = await getClient(args)
- provisioning_session_id = args.provisioning_session_id
- certificate_id = args.certificate_id
- resp: bool = await client.destroyServerCertificate(provisioning_session_id, certificate_id)
- if not resp:
- print('Failed to delete server certificate')
- return 1
- return 0
-
-def format_ContentHostingConfigurationResponse(resp: ContentHostingConfigurationResponse, indent: int = 0) -> str:
- ret = ''
- out_prefix = ' ' * indent
- if resp['ETag'] is not None:
- ret += f'{out_prefix}ETag: {resp["ETag"]}\n'
- if resp['Last-Modified'] is not None:
- ret += f'{out_prefix}Last-Modified: {resp["Last-Modified"]:%b %d %H:%M:%S %Y %Z}\n'
- if resp['Cache-Until'] is not None:
- ret += f'{out_prefix}Cache-Until: {resp["Cache-Until"]:%b %d %H:%M:%S %Y %Z}\n'
- ret += f'''{out_prefix}Provisioning-Session-Id: {resp["ProvisioningSessionId"]}
-
-{out_prefix}{resp["ContentHostingConfiguration"]!r}
-'''
- return ret
-
-async def cmd_hosting_create(args: argparse.Namespace) -> int:
- client = await getClient(args)
- provisioning_session_id = args.provisioning_session_id
- chc_file = args.CHC_JSON_file
- async with aiofiles.open(chc_file, mode='r') as chc_in:
- chc = ContentHostingConfiguration.fromJSON(await chc_in.read())
- resp: Union[bool,ContentHostingConfigurationResponse] = await client.createContentHostingConfiguration(provisioning_session_id,
- chc)
- if isinstance(resp, dict):
- print(format_ContentHostingConfigurationResponse(resp))
- return 0
- if resp:
- print('ContentHostingConfiguration set for provisioning session {provisioning_session_id}')
- return 0
- print('Failed to set ContentHostingConfiguration for provisioning session {provisioning_session_id}')
- return 1
-
-async def cmd_hosting_show(args: argparse.Namespace) -> int:
- client = await getClient(args)
- provisioning_session_id = args.provisioning_session_id
- resp: Optional[ContentHostingConfigurationResponse] = await client.retrieveContentHostingConfiguration(provisioning_session_id)
- if resp is None:
- print('ContentHostingConfiguration not found for provisioning session {provisioning_session_id}')
- return 1
- print(format_ContentHostingConfigurationResponse(resp))
- return 0
-
-async def cmd_hosting_update(args: argparse.Namespace) -> int:
- client = await getClient(args)
- provisioning_session_id = args.provisioning_session_id
- chc_file = args.CHC_JSON_file
- async with aiofiles.open(chc_file, mode='r') as chc_in:
- chc = ContentHostingConfiguration.fromJSON(await chc_in.read())
- resp: bool = await client.updateContentHostingConfiguration(provisioning_session_id, chc)
- if not resp:
- print(f'Failed to update ContentHostingConfiguration for provisioning session {provisioning_session_id}')
- return 1
- print(f'Updated ContentHostingConfiguration for provisioning session {provisioning_session_id}')
- return 0
-
-async def cmd_hosting_delete(args: argparse.Namespace) -> int:
- client = await getClient(args)
- provisioning_session_id = args.provisioning_session_id
- resp: bool = await client.destroyContentHostingConfiguration(provisioning_session_id)
- if not resp:
- print(f'Failed to remove ContentHostingConfiguration for provisioning session {provisioning_session_id}')
- return 1
- print(f'ContentHostingConfiguration for provisioning session {provisioning_session_id} has been removed')
- return 0
-
-async def cmd_hosting_purge(args: argparse.Namespace) -> int:
- client = await getClient(args)
- provisioning_session_id: ResourceId = args.provisioning_session_id
- pattern: Optional[str] = args.path_regex
- resp: Optional[int] = await client.purgeContentHostingCache(provisioning_session_id, pattern)
- if resp is None:
- print('No entries purged')
- else:
- print(f'There were {resp} entries purged from the cache')
- return 0
-
-async def __consumptionReportingConfigurationFromArgs(args: argparse.Namespace) -> ConsumptionReportingConfiguration:
- crc: ConsumptionReportingConfiguration = {}
- if args.interval is not None:
- crc['reportingInterval'] = args.interval
- if args.percentage is not None:
- crc['samplePercentage'] = args.percentage
- if args.locationReport:
- crc['locationReporting'] = True
- if args.accessReport:
- crc['accessReporting'] = True
- return crc
-
-async def cmd_consumption_create(args: argparse.Namespace) -> int:
- client = await getClient(args)
- provisioning_session_id: ResourceId = args.provisioning_session_id
- crc: ConsumptionReportingConfiguration = await __consumptionReportingConfigurationFromArgs(args)
- resp: Union[bool, ConsumptionReportingConfigurationResponse] = await client.activateConsumptionReportingConfiguration(provisioning_session_id, crc)
- if isinstance(resp, bool) and resp or isinstance(resp, ConsumptionReportingConfigurationResponse):
- print('ConsumptionReportingConfiguration created')
- return 0
-
-async def cmd_consumption_show(args: argparse.Namespace) -> int:
- client = await getClient(args)
- provisioning_session_id: ResourceId = args.provisioning_session_id
- try:
- resp: ConsumptionReportingConfigurationResponse = await client.retrieveConsumptionReportingConfiguration(provisioning_session_id)
- print(ConsumptionReportingConfiguration.format(resp['ConsumptionReportingConfiguration']))
- except M1ClientError as err:
- if err.args[1] == 404:
- print('No ConsumptionReportingConfiguration for provisioning session')
- else:
- raise err
- return 0
-
-async def cmd_consumption_update(args: argparse.Namespace) -> int:
- client = await getClient(args)
- provisioning_session_id: ResourceId = args.provisioning_session_id
- crc: ConsumptionReportingConfiguration = await __consumptionReportingConfigurationFromArgs(args)
- resp: bool = await client.updateConsumptionReportingConfiguration(provisioning_session_id, crc)
- if resp:
- print('ConsumptionReportingConfiguration updated')
- else:
- print('ConsumptionReportingConfiguration update failed')
- return 0
-
-async def cmd_consumption_delete(args: argparse.Namespace) -> int:
- client = await getClient(args)
- provisioning_session_id: ResourceId = args.provisioning_session_id
- resp: bool = await client.destroyConsumptionReportingConfiguration(provisioning_session_id)
- if resp:
- print('ConsumptionReportingConfiguration deleted')
- else:
- print('ConsumptionReportingConfiguration failed to delete')
- return 0
-
-async def __policyTemplateFromArgs(args: argparse.Namespace) -> PolicyTemplate:
- with open(args.policy_template,'r') as pol_file:
- return PolicyTemplate.fromJSON(pol_file.read())
-
-async def cmd_policy_create(args: argparse.Namespace) -> int:
- client = await getClient(args)
- provisioning_session_id: ResourceId = args.provisioning_session_id
- policy: PolicyTemplate = await __policyTemplateFromArgs(args)
- resp: Optional[PolicyTemplateResponse] = await client.createPolicyTemplate(provisioning_session_id, policy)
- if resp is None:
- print('PolicyTemplate creation failed: No such provisioning session')
- else:
- print(f'''PolicyTemplate {resp['PolicyTemplate']['policyTemplateId']} created''')
- return 0
-
-async def cmd_policy_show(args: argparse.Namespace) -> int:
- client = await getClient(args)
- provisioning_session_id: ResourceId = args.provisioning_session_id
- policy_template_id: ResourceId = args.policy_template_id
- resp: Optional[PolicyTemplateResponse] = await client.retrievePolicyTemplate(provisioning_session_id, policy_template_id)
- if resp is None:
- print(f'PolicyTemplate "{policy_template_id}" for provisioning session "{provisioning_session_id}" not found')
- else:
- print(f'''{PolicyTemplate.format(resp['PolicyTemplate'])}''')
- return 0
-
-async def cmd_policy_update(args: argparse.Namespace) -> int:
- client = await getClient(args)
- provisioning_session_id: ResourceId = args.provisioning_session_id
- policy_template_id: ResourceId = args.policy_template_id
- policy: PolicyTemplate = await __policyTemplateFromArgs(args)
- resp: bool = await client.updatePolicyTemplate(provisioning_session_id, policy_template_id, policy)
- if resp:
- print('PolicyTemplate updated successfully')
- else:
- print('PolicyTemplate update failed')
- return 0
-
-async def cmd_policy_delete(args: argparse.Namespace) -> int:
- client = await getClient(args)
- provisioning_session_id: ResourceId = args.provisioning_session_id
- policy_template_id: ResourceId = args.policy_template_id
- resp: bool = await client.destroyPolicyTemplate(provisioning_session_id, policy_template_id)
- if resp:
- print('PolicyTemplate deleted')
- else:
- print('Failed to delete policy {policy_template_id} for provisioning session {provisioning_session_id}')
- return 0
-
-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', metavar='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', action='store_true', help='Provisioning session is a downlink')
- parser_provisioning_create_type.add_argument('-u', '--uplink', action='store_true', help='Provisioning session is an uplink')
- parser_provisioning_create.add_argument('external_app_id', metavar='external-app-id', help='The external application id')
- parser_provisioning_create.add_argument('asp_id', metavar='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', metavar='FQDN', nargs='*', help='Reserve a certificate and return the CSR, provide optional extra domain names')
-
- # 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', metavar='certificate-id', help='The certificate id to upload')
- parser_certificates_upload.add_argument('PEM_file', metavar='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.set_defaults(command=cmd_certificates_show)
- parser_certificates_show.add_argument('certificate_id', metavar='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_delete.set_defaults(command=cmd_certificates_delete)
- parser_certificates_delete.add_argument('certificate_id', metavar='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', metavar='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', metavar='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', metavar='path-regex', nargs='?',
- help='Regular expression to match for entries to purge')
-
- # m1-client consumption ...
- parser_consumption = subparsers.add_parser('consumption', help='ConsumptionReportingProvisioing APIs')
- consumption_subparsers = parser_consumption.add_subparsers(required=True)
-
- # m1-client consumption create [-h] [-i ] [-p ] [-l] [-a]
- parser_consumption_create = consumption_subparsers.add_parser('create', parents=[parent_addr_prov],
- help='Activate Consumption Reporting for a provisioning session')
- parser_consumption_create.set_defaults(command=cmd_consumption_create)
- parser_consumption_create.add_argument('-i','--interval', type=int, nargs=1,
- help='The reporting interval for consumption reporting in whole seconds')
- parser_consumption_create.add_argument('-p','--percentage', type=float, nargs=1,
- help='The sample percentage to request for consumption reporting')
- parser_consumption_create.add_argument('-l', '--location-reporting', action='store_true', dest='location_reporting',
- help='Indicates that location reporting should be requested')
- parser_consumption_create.add_argument('-a', '--access-reporting', action='store_true', dest='access_reporting',
- help='Indicates that access reporting should be requested')
-
- # m1-client consumption show [-h]
- parser_consumption_show = consumption_subparsers.add_parser('show', parents=[parent_addr_prov],
- help='Retrieve a ConsumptionReportingConfiguration for a provisioning session')
- parser_consumption_show.set_defaults(command=cmd_consumption_show)
-
- # m1-client consumption update [-h] [-i ] [-p ] [-l] [-a]
- parser_consumption_update = consumption_subparsers.add_parser('update', parents=[parent_addr_prov],
- help='Update Consumption Reporting for a provisioning session')
- parser_consumption_update.set_defaults(command=cmd_consumption_update)
- parser_consumption_update.add_argument('-i','--interval', type=int, nargs=1,
- help='The reporting interval for consumption reporting in whole seconds')
- parser_consumption_update.add_argument('-p','--percentage', type=float, nargs=1,
- help='The sample percentage to request for consumption reporting')
- parser_consumption_update.add_argument('-l', '--location-reporting', action='store_true', dest='location_reporting',
- help='Indicates that location reporting should be requested')
- parser_consumption_update.add_argument('-a', '--access-reporting', action='store_true', dest='access_reporting',
- help='Indicates that access reporting should be requested')
-
- # m1-client consumption delete [-h]
- parser_consumption_delete = consumption_subparsers.add_parser('delete', parents=[parent_addr_prov],
- help='Delete the Consumption Reporting for a provisioning session')
- parser_consumption_delete.set_defaults(command=cmd_consumption_delete)
-
- # m1-client policy ...
- parser_policy = subparsers.add_parser('policy', help='PolicyTemplateProvisioning APIs')
- policy_subparsers = parser_policy.add_subparsers(required=True)
-
- # m1-client policy create [-h]
- parser_policy_create = policy_subparsers.add_parser('create', parents=[parent_addr_prov],
- help='Create a Policy Template for a provisioning session')
- parser_policy_create.set_defaults(command=cmd_policy_create)
- parser_policy_create.add_argument('policy_template', metavar='PolicyTemplate-JSON-file',
- help='Path to a PolicyTemplate JSON file')
-
- # m1-client policy show [-h]
- parser_policy_show = policy_subparsers.add_parser('show', parents=[parent_addr_prov],
- help='Display a Policy Template from a provisioning session')
- parser_policy_show.set_defaults(command=cmd_policy_show)
- parser_policy_show.add_argument('policy_template_id', metavar='policy-template-id',
- help='Id of the Policy Template to display from the provisioning session')
-
- # m1-client policy update [-h]
- parser_policy_update = policy_subparsers.add_parser('update', parents=[parent_addr_prov],
- help='Update a Policy Template for a provisioning session')
- parser_policy_update.set_defaults(command=cmd_policy_update)
- parser_policy_update.add_argument('policy_template_id', metavar='policy-template-id',
- help='Id of the Policy Template to update from the provisioning session')
- parser_policy_update.add_argument('policy_template', metavar='PolicyTemplate-JSON-file',
- help='Path to a PolicyTemplate JSON file')
-
- # m1-client policy delete [-h]
- parser_policy_delete = policy_subparsers.add_parser('delete', parents=[parent_addr_prov],
- help='Delete a PolicyTemplate from a provisioning session')
- parser_policy_delete.set_defaults(command=cmd_policy_delete)
- parser_policy_delete.add_argument('policy_template_id', metavar='policy-template-id',
- help='Id of the Policy Template to delete from the provisioning session')
-
- 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:
- 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
- return 0
-
-def app():
- '''
- Application entry point
- '''
- return asyncio.run(main())
-
-if __name__ == '__main__':
- sys.exit(app())
diff --git a/tools/python3/m1_session_cli.py b/tools/python3/m1_session_cli.py
deleted file mode 100755
index 70f71e8..0000000
--- a/tools/python3/m1_session_cli.py
+++ /dev/null
@@ -1,1154 +0,0 @@
-#!/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 -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-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 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 del-certificate -h
- m1-session-cli del-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 []
- m1-session-cli set-consumption-reporting -h
- m1-session-cli set-consumption-reporting -p [-i ] [-s ] [-l] [-A]
- m1-session-cli show-consumption-reporting -h
- m1-session-cli show-consumption-reporting -p
- m1-session-cli del-consumption-reporting -h
- m1-session-cli del-consumption-reporting -p
- m1-session-cli new-policy-template -h
- m1-session-cli new-policy-template -p -e [-D ] [-S ]
- [--qos-reference ] [--max-up ] [--max-down ]
- [--max-auth-up ] [--max-auth-down ]
- [--default-packet-loss-up ] [--default-packet-loss-down