diff --git a/README.md b/README.md index 03d1c1e..7208119 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This repository holds the 5GMS Application Function implementation for the 5G-MA ## Introduction -The 5GMS application function (AF) is a Network Function that forms part of the 5G Media Services framework as defined +The 5GMS application function (AF) is a Network Function that forms part of the 5G Media Streaming framework as defined in ETSI TS 126.501. This AF uses the [Open5GS](https://open5gs.org/) framework to implement the network function. diff --git a/meson.build b/meson.build index edf9638..45ae8e1 100644 --- a/meson.build +++ b/meson.build @@ -7,7 +7,7 @@ # https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view project('rt-5gms-af', 'c', - version : '1.0.0', + version : '1.0.1', license : '5G-MAG Public', meson_version : '>= 0.47.0', default_options : [ diff --git a/src/5gmsaf/context.c b/src/5gmsaf/context.c index 5ffb778..f2345e6 100644 --- a/src/5gmsaf/context.c +++ b/src/5gmsaf/context.c @@ -8,6 +8,7 @@ program. If this file is missing then the license can be retrieved from https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view */ +#include #include #include #include @@ -19,13 +20,11 @@ int __msaf_log_domain; static OpenAPI_content_hosting_configuration_t *msaf_context_content_hosting_configuration_create(void); static OpenAPI_service_access_information_resource_t *msaf_context_service_access_information_create(char *media_player_entry); -static msaf_provisioning_session_t *msaf_context_provisioning_session_find_by_provisioningSessionId(char *provisioningSessionId); static char *media_player_entry_create(const char *provisioning_session_id, OpenAPI_content_hosting_configuration_t *content_hosting_configuration); static char *url_path_prefix_create(const char *macro, const char *session_id); static char *read_file(const char *filename); static int msaf_context_prepare(void); static int msaf_context_validation(void); -static void msaf_context_get_content_host_config(void); static void msaf_context_display(void); static int ogs_hash_do_per_value(void *fn, const void *key, int klen, const void *value); static void msaf_context_provisioning_session_free(msaf_provisioning_session_t *provisioning_session); @@ -347,11 +346,16 @@ msaf_context_provisioning_session_set() { return msaf_provisioning_session; } -cJSON *msaf_context_retrieve_service_access_information(char *provisioning_session_id) +cJSON *msaf_context_retrieve_service_access_information(const char *provisioning_session_id) { msaf_provisioning_session_t *provisioning_session_context = NULL; provisioning_session_context = msaf_context_provisioning_session_find_by_provisioningSessionId(provisioning_session_id); - if (provisioning_session_context == NULL){ + if (provisioning_session_context == NULL) { + ogs_error("Couldn't find the Provisioning Session ID [%s]", provisioning_session_id); + return NULL; + } + if (provisioning_session_context->serviceAccessInformation == NULL) { + ogs_error("The provisioning Session [%s] does not have an associated Service Access Information", provisioning_session_id); return NULL; } cJSON *service_access_information = OpenAPI_service_access_information_resource_convertToJSON(provisioning_session_context->serviceAccessInformation); @@ -396,14 +400,14 @@ void msaf_context_application_server_print_all() ogs_info("AS %s %s", msaf_as->canonicalHostname, msaf_as->urlPathPrefixFormat); } -/***** Private functions *****/ - -static msaf_provisioning_session_t * -msaf_context_provisioning_session_find_by_provisioningSessionId(char *provisioningSessionId) +msaf_provisioning_session_t * +msaf_context_provisioning_session_find_by_provisioningSessionId(const char *provisioningSessionId) { return ogs_hash_get(self->provisioningSessions_map, provisioningSessionId, OGS_HASH_KEY_STRING); } +/***** Private functions *****/ + static OpenAPI_service_access_information_resource_t * msaf_context_service_access_information_create(char *media_player_entry) { OpenAPI_service_access_information_resource_streaming_access_t *streaming_access @@ -419,10 +423,36 @@ msaf_context_service_access_information_create(char *media_player_entry) { static OpenAPI_content_hosting_configuration_t * msaf_context_content_hosting_configuration_create() { - char *content_host_config_data = read_file(self->config.contentHostingConfiguration); + char *content_host_config_data; + cJSON *content_host_config_json; + + if(!self->config.contentHostingConfiguration) { + ogs_error("contentHostingConfiguration not present in the MSAF configuration file"); + } + + ogs_assert(self->config.contentHostingConfiguration); + + content_host_config_data = read_file(self->config.contentHostingConfiguration); + if (!content_host_config_data) { + ogs_error("The ContentHostingConfiguration JSON file [%s] cannot be opened", self->config.contentHostingConfiguration); + } + ogs_assert(content_host_config_data); + + content_host_config_json = cJSON_Parse(content_host_config_data); + free(content_host_config_data); + + if (content_host_config_json == NULL){ + ogs_error("Parsing contentHostingConfiguration, from file [%s], to JSON structure failed", self->config.contentHostingConfiguration); + } + ogs_assert(content_host_config_json); + OpenAPI_content_hosting_configuration_t *content_hosting_configuration - = OpenAPI_content_hosting_configuration_parseFromJSON(cJSON_Parse(content_host_config_data)); - free (content_host_config_data); + = OpenAPI_content_hosting_configuration_parseFromJSON(content_host_config_json); + + cJSON_Delete(content_host_config_json); + + ogs_assert(content_hosting_configuration); + return content_hosting_configuration; } @@ -434,7 +464,7 @@ media_player_entry_create(const char *session_id, OpenAPI_content_hosting_config static const char macro[] = "{provisioningSessionId}"; char *url_path_prefix = NULL; const char *protocol = "http"; - msaf_application_server_node_t *msaf_as = NULL; + char *domain_name; ogs_assert(session_id); ogs_assert(chc); @@ -447,9 +477,16 @@ media_player_entry_create(const char *session_id, OpenAPI_content_hosting_config } } + if (dist_config->domain_name_alias && strlen(dist_config->domain_name_alias) > 0) { + domain_name = dist_config->domain_name_alias; + } else { + msaf_application_server_node_t *msaf_as; + msaf_as = ogs_list_first(&self->config.applicationServers_list); + domain_name = msaf_as->canonicalHostname; + } + url_path_prefix = url_path_prefix_create(macro, session_id); - msaf_as = ogs_list_first(&self->config.applicationServers_list); /* just use first defined AS for now - change later to use AS picked from pool */ - media_player_entry = ogs_msprintf("%s://%s%s%s", protocol, msaf_as->canonicalHostname, url_path_prefix, self->config.mediaPlayerEntrySuffix); + media_player_entry = ogs_msprintf("%s://%s%s%s", protocol, domain_name, url_path_prefix, self->config.mediaPlayerEntrySuffix); ogs_free(url_path_prefix); @@ -506,7 +543,6 @@ static int msaf_context_validation(void) static void msaf_context_display() { - msaf_application_server_node_t *msaf_as = NULL, *next = NULL; msaf_provisioning_session_t *provisioning_session_context = NULL; provisioning_session_context = msaf_context_provisioning_session_find_by_provisioningSessionId(self->config.provisioningSessionId); ogs_assert(provisioning_session_context); @@ -522,12 +558,19 @@ static char *read_file(const char *filename) /* open in read binary mode */ f = fopen(filename,"rb"); + if (!f) { + ogs_error("Failed to open file %s: %s", filename, strerror(errno)); + return NULL; + } + /* get the length */ fseek(f, 0, SEEK_END); len = ftell(f); fseek(f, 0, SEEK_SET); data_json = (char*)malloc(len + 1); + ogs_assert(data_json); + fread(data_json, 1, len, f); data_json[len] = '\0'; fclose(f); diff --git a/src/5gmsaf/context.h b/src/5gmsaf/context.h index 56ae437..a110a6e 100644 --- a/src/5gmsaf/context.h +++ b/src/5gmsaf/context.h @@ -65,11 +65,12 @@ extern msaf_context_t *msaf_self(void); extern int msaf_context_parse_config(void); extern msaf_provisioning_session_t *msaf_context_provisioning_session_set(void); -extern cJSON *msaf_context_retrieve_service_access_information(char *provisioning_session_id); +extern cJSON *msaf_context_retrieve_service_access_information(const char *provisioning_session_id); extern msaf_application_server_node_t *msaf_context_application_server_add(char *canonical_hostname, char *url_path_prefix_format); extern void msaf_context_application_server_remove(msaf_application_server_node_t *msaf_as); extern void msaf_context_application_server_remove_all(void); extern void msaf_context_application_server_print_all(void); +extern msaf_provisioning_session_t *msaf_context_provisioning_session_find_by_provisioningSessionId(const char *provisioningSessionId); #ifdef __cplusplus } diff --git a/src/5gmsaf/meson.build b/src/5gmsaf/meson.build index 822fa08..c116f90 100644 --- a/src/5gmsaf/meson.build +++ b/src/5gmsaf/meson.build @@ -175,8 +175,7 @@ libmsaf_dep = declare_dependency( msaf_sources = files(''' app.c - ../../subprojects/open5gs/src/main.c -'''.split()) +'''.split()) + open5gs_project.get_variable('app_main_c') executable('open5gs-msafd', sources : msaf_sources, diff --git a/src/5gmsaf/msaf-sm.c b/src/5gmsaf/msaf-sm.c index d427f8e..feb382d 100644 --- a/src/5gmsaf/msaf-sm.c +++ b/src/5gmsaf/msaf-sm.c @@ -11,7 +11,8 @@ program. If this file is missing then the license can be retrieved from #include "sbi-path.h" // #include "nnrf-handler.h" -cJSON *msaf_context_retrieve_service_access_information(char *provisioning_session_id); +cJSON *msaf_context_retrieve_service_access_information(const char *provisioning_session_id); +msaf_provisioning_session_t *msaf_context_provisioning_session_find_by_provisioningSessionId(const char *provisioning_session_id); void msaf_state_initial(ogs_fsm_t *s, msaf_event_t *e) { @@ -123,25 +124,52 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) CASE("service-access-information") SWITCH(message.h.method) CASE(OGS_SBI_HTTP_METHOD_GET) - cJSON *service_access_information = NULL; - service_access_information = msaf_context_retrieve_service_access_information(message.h.resource.component[1]); - if (service_access_information != NULL){ - ogs_sbi_response_t *response = NULL; - response = ogs_sbi_response_new(); - response->http.content_length = strlen(cJSON_Print(service_access_information)); - response->http.content = cJSON_Print(service_access_information); - response->status = 200; - ogs_sbi_header_set(response->http.headers,"Content-Type", "application/json"); - ogs_assert(response); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - } else { - char *err = NULL; - asprintf(&err,"Service Access Information %s not found.", message.h.resource.component[1]); - ogs_error("Client requested invalid Service Access Information [%s]", message.h.resource.component[1]); - ogs_assert(true == - ogs_sbi_server_send_error(stream, - 404, &message, - "Service Access Information not found", err)); + cJSON *service_access_information = NULL; + msaf_provisioning_session_t *msaf_provisioning_session = NULL; + msaf_provisioning_session = msaf_context_provisioning_session_find_by_provisioningSessionId(message.h.resource.component[1]); + + if (!msaf_provisioning_session) { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] not found.", message.h.resource.component[1]); + ogs_error("Client requested invalid Provisioning Session [%s]", message.h.resource.component[1]); + ogs_assert(true == ogs_sbi_server_send_error(stream, + 404, &message, + "Provisioning Session not found", + err)); + break; + } + + if (msaf_provisioning_session->serviceAccessInformation) { + service_access_information = msaf_context_retrieve_service_access_information(message.h.resource.component[1]); + if (service_access_information != NULL) { + ogs_sbi_response_t *response; + char *text; + response = ogs_sbi_response_new(); + text = cJSON_Print(service_access_information); + response->http.content_length = strlen(text); + response->http.content = text; + response->status = 200; + ogs_sbi_header_set(response->http.headers, "Content-Type", "application/json"); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + cJSON_Delete(service_access_information); + } else { + char *err = NULL; + asprintf(&err,"Service Access Information for the Provisioning Session [%s] not found.", message.h.resource.component[1]); + ogs_error("Client requested invalid Service Access Information for the Provisioning Session [%s]", message.h.resource.component[1]); + ogs_assert(true == ogs_sbi_server_send_error(stream, + 404, &message, + "Service Access Information not found", + err)); + } + } else { + char *err = NULL; + asprintf(&err,"Provisioning Session [%s] has no Service Access Information associated with it.", message.h.resource.component[1]); + ogs_error("Provisioning Session [%s] has no Service Access Information associated with it", message.h.resource.component[1]); + ogs_assert(true == ogs_sbi_server_send_error(stream, + 404, &message, + "Service Access Information not found", + err)); } break; @@ -327,3 +355,6 @@ void msaf_state_functional(ogs_fsm_t *s, msaf_event_t *e) break; } } + +/* vim:ts=8:sts=4:sw=4:expandtab: + */ diff --git a/subprojects/patch_open5gs.sh b/subprojects/patch_open5gs.sh index 1041d80..d5012d5 100755 --- a/subprojects/patch_open5gs.sh +++ b/subprojects/patch_open5gs.sh @@ -32,6 +32,17 @@ if ! grep -q '/\* rt-5gms-applicatiopn-function patch applied \*/' "$open5gs_src ogs_sbi_server_actions = ogs_mhd_server_actions; #endif } +--- open5gs.orig/src/meson.build ++++ open5gs/src/meson.build +@@ -29,6 +29,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') EOF ) fi