Solve problems found in the first round of internal test

The major changes are for more TR-104 compliant.
- Changes those static objects to dynamic ones although they can have only one instance
- Make some paraters' values compliant to the data model
This commit is contained in:
Yalu Zhang 2020-09-24 15:00:56 +02:00 committed by Amin Ben Ramdhane
parent 6566c2baf7
commit 85eca6e6dc
8 changed files with 311 additions and 94 deletions

View file

@ -109,7 +109,6 @@ int init_call_log()
// Check if there are any new call logs since the last time
if (stat(CALL_LOG_FILE, &cur_stat) == 0) {
if (memcmp(&cur_stat, &prev_stat, sizeof(cur_stat)) == 0) {
TR104_DEBUG("There are no new call log since the last time. Exit.\n");
return 0;
} else {
prev_stat = cur_stat;
@ -280,3 +279,29 @@ __ret:
return res;
#undef CHECK_RESULT
}
// Get the UCI section name of a codec, e.g. G.711ALaw --> alaw
const char *get_codec_uci_name(const char *codec)
{
if (codec && *codec) {
for (int i = 0; i < codecs_num; i++) {
if (!strcasecmp(supported_codecs[i].codec, codec))
return supported_codecs[i].uci_name;
}
}
return NULL;
}
// Get the codec name in TR-104 from UCI section name, e.g. alaw --> G.711ALaw
const char *get_codec_name(const char *codec_profile)
{
if (codec_profile && *codec_profile) {
for (int i = 0; i < codecs_num; i++) {
if (!strcasecmp(supported_codecs[i].uci_name, codec_profile))
return supported_codecs[i].codec;
}
}
return NULL;
}

View file

@ -64,3 +64,5 @@ extern char *KeyingMethods[];
int init_supported_codecs();
int init_call_log();
const char *get_codec_uci_name(const char *codec);
const char *get_codec_name(const char *codec_profile);

View file

@ -61,29 +61,43 @@ static int browseServicesVoiceServiceCodecProfileInst(struct dmctx *dmctx, DMNOD
char *inst = NULL, *inst_last = NULL;
struct dmmap_dup *p;
LIST_HEAD(dup_list);
int i;
int i, j;
int has_codec_profile = 0;
// Initialize supported codecs if it has not been done
if (codecs_num <= 0)
init_supported_codecs();
// Populate all supported codecs in UCI
for (i = 0; i < codecs_num; i++) {
struct codec_info *codec = &supported_codecs[i];
char *value = NULL;
// Populate all supported codecs to UCI if there is none
for (j = 0; j < 2; j++) {
for (i = 0; i < codecs_num; i++) {
struct codec_info *codec = &supported_codecs[i];
char *value = NULL;
dmuci_get_option_value_string(TR104_UCI_PACKAGE, codec->uci_name, "name", &value);
if (!value || !*value) {
char str[16];
// Not found. Add this codec in the UCI
dmuci_set_value(TR104_UCI_PACKAGE, codec->uci_name, "", "codec_profile");
TR104_DEBUG("Created a UCI section: %s\n", str);
dmuci_set_value(TR104_UCI_PACKAGE, codec->uci_name, "name", codec->codec);
snprintf(str, sizeof(str), "%u", codec->ptime_default);
dmuci_set_value(TR104_UCI_PACKAGE, codec->uci_name, "ptime", str);
} else {
dmfree(value);
dmuci_get_option_value_string(TR104_UCI_PACKAGE, codec->uci_name, "name", &value);
if (!value || !*value) {
if (j == 1) {
char str[16];
// Not found. Add this codec in the UCI
dmuci_set_value(TR104_UCI_PACKAGE, codec->uci_name, "", "codec_profile");
TR104_DEBUG("Created a UCI section: %s\n", str);
dmuci_set_value(TR104_UCI_PACKAGE, codec->uci_name, "name", codec->codec);
snprintf(str, sizeof(str), "%u", codec->ptime_default);
dmuci_set_value(TR104_UCI_PACKAGE, codec->uci_name, "ptime", str);
}
} else {
dmfree(value);
if (j == 0) {
// At least there is one codec profile configured in UCI
has_codec_profile = 1;
break;
}
}
}
// Don't add any profile if there is any in UCI which has been configured
if (has_codec_profile)
break;
}
synchronize_specific_config_sections_with_dmmap("asterisk", "codec_profile", "dmmap_asterisk", &dup_list);
@ -149,7 +163,7 @@ static int delObjServicesVoiceServiceVoIPProfile(char *refparam, struct dmctx *c
return 0;
}
int addObjServicesVoiceServiceCodecProfile(char *refparam, struct dmctx *ctx, void *data, char **instance)
static int addObjServicesVoiceServiceCodecProfile(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
char *inst, *value, *v;
struct uci_section *dmmap = NULL, *s = NULL;
@ -164,7 +178,7 @@ int addObjServicesVoiceServiceCodecProfile(char *refparam, struct dmctx *ctx, vo
return 0;
}
int delObjServicesVoiceServiceCodecProfile(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
static int delObjServicesVoiceServiceCodecProfile(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
struct uci_section *s = NULL, *ss = NULL, *dmmap_section = NULL;
int found = 0;
@ -256,7 +270,7 @@ DMOBJ tServicesVoiceServiceObj[] = {
{"CallControl", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tServicesVoiceServiceCallControlObj, NULL, NULL, BBFDM_BOTH},
{"CallLog", &DMREAD, NULL, NULL, NULL, browseServicesVoiceServiceCallLogInst, NULL, NULL, NULL, NULL, tServicesVoiceServiceCallLogParams, NULL, BBFDM_BOTH},
{"VoIPProfile", &DMWRITE, addObjServicesVoiceServiceVoIPProfile, delObjServicesVoiceServiceVoIPProfile, NULL, browseServicesVoiceServiceVoIPProfileInst, NULL, NULL, NULL, tServicesVoiceServiceVoIPProfileObj, tServicesVoiceServiceVoIPProfileParams, NULL, BBFDM_BOTH},
{"CodecProfile", &DMWRITE, NULL, NULL, NULL, browseServicesVoiceServiceCodecProfileInst, NULL, NULL, NULL, NULL, tServicesVoiceServiceCodecProfileParams, NULL, BBFDM_BOTH},
{"CodecProfile", &DMWRITE, addObjServicesVoiceServiceCodecProfile, delObjServicesVoiceServiceCodecProfile, NULL, browseServicesVoiceServiceCodecProfileInst, NULL, NULL, NULL, NULL, tServicesVoiceServiceCodecProfileParams, NULL, BBFDM_BOTH},
{0}
};

View file

@ -68,6 +68,46 @@ static int browseServicesVoiceServiceCallControlOutgoingMapInst(struct dmctx *dm
return 0;
}
/*#Device.Services.VoiceService.{i}.CallControl.NumberingPlan.{i}.!UCI:asterisk/tel_advanced/dmmap_asterisk*/
static int browseServicesVoiceServiceCallControlNumberingPlanInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
char *inst = NULL, *max_inst = NULL;
struct dmmap_dup *p;
LIST_HEAD(dup_list);
synchronize_specific_config_sections_with_dmmap("asterisk", "tel_advanced", "dmmap_asterisk", &dup_list);
list_for_each_entry(p, &dup_list, list) {
inst = handle_update_instance(1, dmctx, &max_inst, update_instance_alias, 5,
p->dmmap_section, "numberingplaninstance", "numberingplanalias", "dmmap_asterisk", "tel_advanced");
if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)p->config_section, inst) == DM_STOP)
break;
}
free_dmmap_config_dup_list(&dup_list);
return 0;
}
/*#Device.Services.VoiceService.{i}.CallControl.CallingFeatures.Set.{i}.!UCI:asterisk/advanced_features/dmmap_asterisk*/
static int browseServicesVoiceServiceCallControlCallingFeaturesSetInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
char *inst = NULL, *max_inst = NULL;
struct dmmap_dup *p;
LIST_HEAD(dup_list);
synchronize_specific_config_sections_with_dmmap("asterisk", "advanced_features", "dmmap_asterisk", &dup_list);
list_for_each_entry(p, &dup_list, list) {
inst = handle_update_instance(1, dmctx, &max_inst, update_instance_alias, 5,
p->dmmap_section, "setinstance", "setalias", "dmmap_asterisk", "advanced_features");
if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)p->config_section, inst) == DM_STOP)
break;
}
free_dmmap_config_dup_list(&dup_list);
return 0;
}
/*#Device.Services.VoiceService.{i}.CallControl.CallingFeatures.Set.SCREJ.{i}.!UCI:asterisk/call_filter_rule_incoming/dmmap_asterisk*/
static int browseServicesVoiceServiceCallControlCallingFeaturesSetSCREJInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
@ -143,50 +183,13 @@ static int delObjServicesVoiceServiceCallControlNumberingPlan(char *refparam, st
static int addObjServicesVoiceServiceCallControlCallingFeaturesSet(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
char *inst, *value, *v;
struct uci_section *dmmap = NULL, *s = NULL;
check_create_dmmap_package("dmmap_asterisk");
inst = get_last_instance_bbfdm("dmmap_asterisk", "advanced_features", "setinstance");
dmuci_add_section_and_rename("asterisk", "advanced_features", &s, &value);
dmuci_add_section_bbfdm("dmmap_asterisk", "advanced_features", &dmmap, &v);
dmuci_set_value_by_section(dmmap, "section_name", section_name(s));
*instance = update_instance(inst, 4, dmmap, "setinstance", "dmmap_asterisk", "advanced_features");
TR104_DEBUG("VoiceService.1.CallControl.CallingFeatures.Set. has only one instance so it can't be added or deleted\n");
return 0;
}
static int delObjServicesVoiceServiceCallControlCallingFeaturesSet(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
struct uci_section *s = NULL, *ss = NULL, *dmmap_section = NULL;
int found = 0;
switch (del_action) {
case DEL_INST:
get_dmmap_section_of_config_section("dmmap_asterisk", "advanced_features", section_name((struct uci_section *)data), &dmmap_section);
if (dmmap_section != NULL)
dmuci_delete_by_section(dmmap_section, NULL, NULL);
dmuci_delete_by_section((struct uci_section *)data, NULL, NULL);
break;
case DEL_ALL:
uci_foreach_sections("asterisk", "advanced_features", s) {
if (found != 0) {
get_dmmap_section_of_config_section("dmmap_asterisk", "advanced_features", section_name(ss), &dmmap_section);
if (dmmap_section != NULL)
dmuci_delete_by_section(dmmap_section, NULL, NULL);
dmuci_delete_by_section(ss, NULL, NULL);
}
ss = s;
found++;
}
if (ss != NULL) {
get_dmmap_section_of_config_section("dmmap_asterisk", "advanced_features", section_name(ss), &dmmap_section);
if (dmmap_section != NULL)
dmuci_delete_by_section(dmmap_section, NULL, NULL);
dmuci_delete_by_section(ss, NULL, NULL);
}
break;
}
TR104_DEBUG("VoiceService.1.CallControl.CallingFeatures.Set. has only one instance so it can't be added or deleted\n");
return 0;
}
@ -294,42 +297,114 @@ static int set_ServicesVoiceServiceCallControlLine_DirectoryNumber(char *refpara
}
/*#Device.Services.VoiceService.{i}.CallControl.Line.{i}.Provider!UCI:asterisk/tel_line,@i-1/sip_account*/
#define SIP_CLIENT_PATH "Device.Services.VoiceService.1.SIP.Client."
#define SIP_CLIENT_PATH_LEN strlen(SIP_CLIENT_PATH)
static int get_ServicesVoiceServiceCallControlLine_Provider(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_value_by_section_string((struct uci_section *)data, "sip_account", value);
char *tmp = NULL;
*value = "";
dmuci_get_value_by_section_string((struct uci_section *)data, "sip_account", &tmp);
if (tmp && strlen(tmp) > 3 && strncmp(tmp, "sip", 3) == 0) {
dmasprintf(value, SIP_CLIENT_PATH"%d", atoi(tmp + 3) + 1);
dmfree(tmp);
}
return 0;
}
static int set_ServicesVoiceServiceCallControlLine_Provider(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
char *tmp;
switch (action) {
case VALUECHECK:
if (dm_validate_string(value, -1, 256, NULL, 0, NULL, 0))
return FAULT_9007;
break;
if (strlen(value) > SIP_CLIENT_PATH_LEN &&
strncmp(value, SIP_CLIENT_PATH, SIP_CLIENT_PATH_LEN) == 0 &&
atoi(value + SIP_CLIENT_PATH_LEN) > 0) {
return 0;
}
return FAULT_9007;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "sip_account", value);
dmasprintf(&tmp, "sip%d", atoi(value + SIP_CLIENT_PATH_LEN) - 1);
dmuci_set_value_by_section((struct uci_section *)data, "sip_account", tmp);
break;
}
return 0;
}
/*#Device.Services.VoiceService.{i}.CallControl.IncomingMap.{i}.Line!UCI:asterisk/sip_service_provider,@i-1/call_lines*/
#define CALL_CONTROL_LINE "Device.Services.VoiceService.1.CallControl.Line."
#define CALL_CONTROL_LINE_LEN strlen(CALL_CONTROL_LINE)
static int get_ServicesVoiceServiceCallControlIncomingMap_Line(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_value_by_section_string((struct uci_section *)data, "call_lines", value);
char *tmp = NULL;
char buf[256] = "";
*value = "";
dmuci_get_value_by_section_string((struct uci_section *)data, "call_lines", &tmp);
if (tmp && *tmp) {
char *token, *saveptr;
int len = 0;
for (token = strtok_r(tmp, " ", &saveptr); token; token = strtok_r(NULL, " ", &saveptr)) {
int line_index = atoi(token);
if (line_index >= 0 && len < sizeof(buf)) {
int res = snprintf(buf + len, sizeof(buf) - len, "%s"CALL_CONTROL_LINE"%d",
len == 0 ? "" : ",", line_index + 1);
if (res <= 0) {
TR104_DEBUG("buf might be too small\n");
dmfree(tmp);
return FAULT_9002;
}
len += res;
}
}
if (buf[0] != '\0')
*value = dmstrdup(buf);
dmfree(tmp);
}
return 0;
}
static int set_ServicesVoiceServiceCallControlIncomingMap_Line(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
char *token, *saveptr, *dup;
char buf[256] = "";
int len = 0;
switch (action) {
case VALUECHECK:
if (dm_validate_string(value, -1, 256, NULL, 0, NULL, 0))
return FAULT_9007;
// Duplicate the original value because strtok_r() might truncate it if there are multiple lines to set
if ((dup = dmstrdup(value)) == NULL)
return FAULT_9002;
for (token = strtok_r(dup, ", ", &saveptr); token; token = strtok_r(NULL, ", ", &saveptr)) {
if (strlen(token) <= CALL_CONTROL_LINE_LEN ||
strncmp(token, CALL_CONTROL_LINE, CALL_CONTROL_LINE_LEN) != 0 ||
atoi(token + CALL_CONTROL_LINE_LEN) <= 0) {
TR104_DEBUG("wrong CallControl.Line format: [%s]\n", token);
dmfree(dup);
return FAULT_9007;
}
}
dmfree(dup);
break;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "call_lines", value);
for (token = strtok_r(value, ", ", &saveptr); token; token = strtok_r(NULL, ", ", &saveptr)) {
int inst = atoi(token + CALL_CONTROL_LINE_LEN);
if (inst > 0 && len < sizeof(buf)) {
int res = snprintf(buf + len, sizeof(buf) - len, "%s%d", len == 0 ? "" : " ", inst - 1);
if (res <= 0) {
TR104_DEBUG("buf might be too small\n");
return FAULT_9002;
}
len += res;
}
}
if (buf[0] != '\0')
dmuci_set_value_by_section((struct uci_section *)data, "call_lines", buf);
break;
}
return 0;
@ -458,7 +533,7 @@ DMOBJ tServicesVoiceServiceCallControlObj[] = {
{"Line", &DMWRITE, addObjServicesVoiceServiceCallControlLine, delObjServicesVoiceServiceCallControlLine, NULL, browseServicesVoiceServiceCallControlLineInst, NULL, NULL, NULL, NULL, tServicesVoiceServiceCallControlLineParams, NULL, BBFDM_BOTH},
{"IncomingMap", &DMWRITE, addObjServicesVoiceServiceCallControlIncomingMap, delObjServicesVoiceServiceCallControlIncomingMap, NULL, browseServicesVoiceServiceCallControlIncomingMapInst, NULL, NULL, NULL, NULL, tServicesVoiceServiceCallControlIncomingMapParams, NULL, BBFDM_BOTH},
{"OutgoingMap", &DMWRITE, addObjServicesVoiceServiceCallControlOutgoingMap, delObjServicesVoiceServiceCallControlOutgoingMap, NULL, browseServicesVoiceServiceCallControlOutgoingMapInst, NULL, NULL, NULL, NULL, tServicesVoiceServiceCallControlOutgoingMapParams, NULL, BBFDM_BOTH},
{"NumberingPlan", &DMWRITE, addObjServicesVoiceServiceCallControlNumberingPlan, delObjServicesVoiceServiceCallControlNumberingPlan, NULL, NULL, NULL, NULL, NULL, NULL, tServicesVoiceServiceCallControlNumberingPlanParams, NULL, BBFDM_BOTH},
{"NumberingPlan", &DMWRITE, addObjServicesVoiceServiceCallControlNumberingPlan, delObjServicesVoiceServiceCallControlNumberingPlan, NULL, browseServicesVoiceServiceCallControlNumberingPlanInst, NULL, NULL, NULL, NULL, tServicesVoiceServiceCallControlNumberingPlanParams, NULL, BBFDM_BOTH},
{"CallingFeatures", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tServicesVoiceServiceCallControlCallingFeaturesObj, NULL, NULL, BBFDM_BOTH},
{0}
};
@ -498,7 +573,7 @@ DMLEAF tServicesVoiceServiceCallControlNumberingPlanParams[] = {
/* *** Device.Services.VoiceService.{i}.CallControl.CallingFeatures. *** */
DMOBJ tServicesVoiceServiceCallControlCallingFeaturesObj[] = {
/* OBJ, permission, addobj, delobj, checkobj, browseinstobj, forced_inform, notification, nextdynamicobj, nextobj, leaf, linker, bbfdm_type*/
{"Set", &DMWRITE, addObjServicesVoiceServiceCallControlCallingFeaturesSet, delObjServicesVoiceServiceCallControlCallingFeaturesSet, NULL, NULL, NULL, NULL, NULL, tServicesVoiceServiceCallControlCallingFeaturesSetObj, tServicesVoiceServiceCallControlCallingFeaturesSetParams, NULL, BBFDM_BOTH},
{"Set", &DMWRITE, addObjServicesVoiceServiceCallControlCallingFeaturesSet, delObjServicesVoiceServiceCallControlCallingFeaturesSet, NULL, browseServicesVoiceServiceCallControlCallingFeaturesSetInst, NULL, NULL, NULL, tServicesVoiceServiceCallControlCallingFeaturesSetObj, tServicesVoiceServiceCallControlCallingFeaturesSetParams, NULL, BBFDM_BOTH},
{0}
};

View file

@ -98,19 +98,19 @@ static int get_ServicesVoiceServiceCapabilitiesSIPClient_TLSAuthenticationKeySiz
static int get_ServicesVoiceServiceCapabilitiesSIPClient_TLSEncryptionProtocols(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
*value = "AES,Blowfish,Camellia,SEED,CAST-128,IDEA,RC5,3DES,SM4";
*value = "AES,Camellia,3DES";
return 0;
}
static int get_ServicesVoiceServiceCapabilitiesSIPClient_TLSEncryptionKeySizes(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
*value = "256,32-448,256,128,40-128,128,128,168,128";
*value = "256,256,168";
return 0;
}
static int get_ServicesVoiceServiceCapabilitiesSIPClient_TLSKeyExchangeProtocols(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
*value = "RSA,DSA,DiffieHellman key exchange,Elliptic curve,X25519,Ed25519,X448,Ed448,SM2";
*value = "RSA";
return 0;
}

View file

@ -21,6 +21,31 @@ static int get_ServicesVoiceServiceCodecProfile_Codec(char *refparam, struct dmc
return 0;
}
static int set_ServicesVoiceServiceCodecProfile_Codec(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
int i;
const char *uci_name;
switch (action) {
case VALUECHECK:
for (i = 0; i < codecs_num; i++) {
if (strcmp(supported_codecs[i].codec, value) == 0)
return 0;
}
TR104_DEBUG("Wrong codec: [%s]\n", value);
return FAULT_9007;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "name", value);
// The UCI section name must be changed accordingly. Otherwise it can not be referenced correctly
uci_name = get_codec_uci_name(value);
if (uci_name) {
dmuci_rename_section_by_section((struct uci_section *)data, (char *)uci_name);
}
break;
}
return 0;
}
/*#Device.Services.VoiceService.{i}.CodecProfile.{i}.PacketizationPeriod!UCI:asterisk/codec_profile,@i-1/ptime*/
static int get_ServicesVoiceServiceCodecProfile_PacketizationPeriod(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
@ -48,7 +73,7 @@ static int set_ServicesVoiceServiceCodecProfile_PacketizationPeriod(char *refpar
/* *** Device.Services.VoiceService.{i}.CodecProfile.{i}. *** */
DMLEAF tServicesVoiceServiceCodecProfileParams[] = {
/* PARAM, permission, type, getvalue, setvalue, forced_inform, notification, bbfdm_type*/
{"Codec", &DMREAD, DMT_STRING, get_ServicesVoiceServiceCodecProfile_Codec, NULL, NULL, NULL, BBFDM_BOTH},
{"Codec", &DMWRITE, DMT_STRING, get_ServicesVoiceServiceCodecProfile_Codec, set_ServicesVoiceServiceCodecProfile_Codec, NULL, NULL, BBFDM_BOTH},
{"PacketizationPeriod", &DMWRITE, DMT_STRING, get_ServicesVoiceServiceCodecProfile_PacketizationPeriod, set_ServicesVoiceServiceCodecProfile_PacketizationPeriod, NULL, NULL, BBFDM_BOTH},
{0}
};

View file

@ -32,6 +32,15 @@ static int browseServicesVoiceServiceSIPClientInst(struct dmctx *dmctx, DMNODE *
return 0;
}
/*#Device.Services.VoiceService.{i}.SIP.Client.{i}.Contact.1*/
static int browseServicesVoiceServiceSIPClientContactInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
// prev_data is from its parent node SIP.Client.{i}. i.e. the UCI section of asterisk.sip_service_provider
DM_LINK_INST_OBJ(dmctx, parent_node, prev_data, "1");
return 0;
}
/*#Device.Services.VoiceService.{i}.SIP.Network.{i}.!UCI:asterisk/sip_service_provider/dmmap_asterisk*/
static int browseServicesVoiceServiceSIPNetworkInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
@ -50,6 +59,14 @@ static int browseServicesVoiceServiceSIPNetworkInst(struct dmctx *dmctx, DMNODE
return 0;
}
/*#Device.Services.VoiceService.{i}.SIP.Network.{i}.FQDNServer.1*/
static int browseServicesVoiceServiceSIPNetworkFQDNServerInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
// prev_data is from its parent node SIP.Network.{i}. i.e. a UCI section of asterisk.sip_service_provider
DM_LINK_INST_OBJ(dmctx, parent_node, prev_data, "1");
return 0;
}
/*************************************************************
* ADD & DEL OBJ
**************************************************************/
@ -354,6 +371,11 @@ static int get_ServicesVoiceServiceSIPClientContact_ExpireTime(char *refparam, s
struct uci_section *section = (struct uci_section *)data;
json_object *res = NULL, *sip, *client;
if (!section) {
TR104_DEBUG("section shall NOT be null\n");
return 0;
}
dmubus_call("voice.asterisk", "status", UBUS_ARGS{}, 0, &res);
if (res) {
sip = dmjson_get_obj(res, 1, "sip");
@ -383,6 +405,10 @@ static int get_ServicesVoiceServiceSIPClientContact_ExpireTime(char *refparam, s
}
time_expires = time_last + period;
*value = dmstrdup(ctime_r(&time_expires, buf));
// ctime_r() strangely adds a return at the end, e.g. "Fri Sep 25 12:24:39 2020\n". Remove it
char *tmp = strchr(*value, '\n');
if (tmp)
*tmp = '\0';
} else {
TR104_DEBUG("Unexpected time format: %s\n", last_reg_time);
}
@ -401,6 +427,11 @@ static int get_ServicesVoiceServiceSIPClientContact_UserAgent(char *refparam, st
struct uci_section *section = (struct uci_section *)data;
json_object *res = NULL, *sip, *client;
if (!section) {
TR104_DEBUG("section shall NOT be null\n");
return 0;
}
dmubus_call("voice.asterisk", "status", UBUS_ARGS{}, 0, &res);
if (res) {
sip = dmjson_get_obj(res, 1, "sip");
@ -577,6 +608,11 @@ static int set_ServicesVoiceServiceSIPNetwork_ProxyServerPort(char *refparam, st
static int get_ServicesVoiceServiceSIPNetwork_ProxyServerTransport(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_value_by_section_string((struct uci_section *)data, "transport", value);
if (*value && **value) {
// Convert to uppercase
for (char *ch = *value; *ch != '\0'; ch++)
*ch = toupper(*ch);
}
return 0;
}
@ -640,6 +676,10 @@ static int set_ServicesVoiceServiceSIPNetwork_RegistrarServerPort(char *refparam
static int get_ServicesVoiceServiceSIPNetwork_RegistrarServerTransport(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_value_by_section_string((struct uci_section *)data, "transport", value);
if (*value && **value) {
for (char *ch = *value; *ch != '\0'; ch++)
*ch = toupper(*ch);
}
return 0;
}
@ -826,30 +866,36 @@ static int set_ServicesVoiceServiceSIPNetwork_DSCPMark(char *refparam, struct dm
/*#Device.Services.VoiceService.{i}.SIP.Network.{i}.CodecList!UCI:asterisk/sip_service_provider,@i-1/codecs*/
static int get_ServicesVoiceServiceSIPNetwork_CodecList(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_value_by_section_string((struct uci_section *)data, "codecs", value);
if (*value && **value) {
// Replace ' ' with ',' as per TR-104 syntax
for (char *ch = *value; *ch; ch++) {
if (*ch == ' ')
*ch = ',';
char *tmp = NULL;
*value = "";
dmuci_get_value_by_section_string((struct uci_section *)data, "codecs", &tmp);
if (tmp && *tmp) {
char buf[256] = "";
char *token, *saveptr;
int len = 0;
for (token = strtok_r(tmp, ", ", &saveptr); token; token = strtok_r(NULL, ", ", &saveptr)) {
const char *codec = get_codec_name(token);
if (codec && len < sizeof(buf)) {
int res = snprintf(buf + len, sizeof(buf) - len, "%s%s", len == 0 ? "" : ",", codec);
if (res <= 0) {
TR104_DEBUG("buf might be too small\n");
dmfree(tmp);
return FAULT_9002;
}
len += res;
}
}
if (buf[0] != '\0')
*value = dmstrdup(buf);
dmfree(tmp);
}
return 0;
}
// Get the UCI section name of a codec, e.g. G.711ALaw --> alaw
static const char *get_codec_uci_name(const char *codec)
{
if (codec && *codec) {
for (int i = 0; i < codecs_num; i++) {
if (!strcasecmp(supported_codecs[i].codec, codec))
return supported_codecs[i].uci_name;
}
}
return NULL;
}
static int del_codec_list(struct uci_section * section)
{
char *codec_list = NULL, *token, *saveptr;
@ -942,11 +988,19 @@ static int get_ServicesVoiceServiceSIPNetworkFQDNServer_Origin(char *refparam, s
/*#Device.Services.VoiceService.{i}.SIP.Network.{i}.FQDNServer.Domain!UCI:asterisk/sip_service_provider,@i-1/domain*/
static int get_ServicesVoiceServiceSIPNetworkFQDNServer_Domain(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
if (!data) {
TR104_DEBUG("data shall NOT be null\n");
return 0;
}
return get_server_address(data, "domain", value);
}
static int set_ServicesVoiceServiceSIPNetworkFQDNServer_Domain(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
if (!data) {
TR104_DEBUG("data shall NOT be null\n");
return 0;
}
switch (action) {
case VALUECHECK:
if (dm_validate_string(value, -1, 256, NULL, 0, NULL, 0))
@ -962,11 +1016,19 @@ static int set_ServicesVoiceServiceSIPNetworkFQDNServer_Domain(char *refparam, s
/*#Device.Services.VoiceService.{i}.SIP.Network.{i}.FQDNServer.Port!UCI:asterisk/sip_service_provider,@i-1/domain*/
static int get_ServicesVoiceServiceSIPNetworkFQDNServer_Port(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
if (!data) {
TR104_DEBUG("data shall NOT be null\n");
return 0;
}
return get_server_port(data, "domain", value);
}
static int set_ServicesVoiceServiceSIPNetworkFQDNServer_Port(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
if (!data) {
TR104_DEBUG("data shall NOT be null\n");
return 0;
}
switch (action) {
case VALUECHECK:
if (dm_validate_unsignedInt(value, RANGE_ARGS{{"0","65535"}}, 1))
@ -993,7 +1055,7 @@ DMOBJ tServicesVoiceServiceSIPObj[] = {
/* *** Device.Services.VoiceService.{i}.SIP.Client.{i}. *** */
DMOBJ tServicesVoiceServiceSIPClientObj[] = {
/* OBJ, permission, addobj, delobj, checkobj, browseinstobj, forced_inform, notification, nextdynamicobj, nextobj, leaf, linker, bbfdm_type*/
{"Contact", &DMWRITE, addObjServicesVoiceServiceSIPClientContact, delObjServicesVoiceServiceSIPClientContact, NULL, NULL, NULL, NULL, NULL, NULL, tServicesVoiceServiceSIPClientContactParams, NULL, BBFDM_BOTH},
{"Contact", &DMWRITE, addObjServicesVoiceServiceSIPClientContact, delObjServicesVoiceServiceSIPClientContact, NULL, browseServicesVoiceServiceSIPClientContactInst, NULL, NULL, NULL, NULL, tServicesVoiceServiceSIPClientContactParams, NULL, BBFDM_BOTH},
{0}
};
@ -1008,7 +1070,7 @@ DMLEAF tServicesVoiceServiceSIPClientParams[] = {
{0}
};
/* *** Device.Services.VoiceService.{i}.SIP.Client.{i}.Contact. *** */
/* *** Device.Services.VoiceService.{i}.SIP.Client.{i}.Contact.{i}. *** */
DMLEAF tServicesVoiceServiceSIPClientContactParams[] = {
/* PARAM, permission, type, getvalue, setvalue, forced_inform, notification, bbfdm_type*/
{"Origin", &DMREAD, DMT_STRING, get_ServicesVoiceServiceSIPClientContact_Origin, NULL, NULL, NULL, BBFDM_BOTH},
@ -1021,7 +1083,7 @@ DMLEAF tServicesVoiceServiceSIPClientContactParams[] = {
/* *** Device.Services.VoiceService.{i}.SIP.Network.{i}. *** */
DMOBJ tServicesVoiceServiceSIPNetworkObj[] = {
/* OBJ, permission, addobj, delobj, checkobj, browseinstobj, forced_inform, notification, nextdynamicobj, nextobj, leaf, linker, bbfdm_type*/
{"FQDNServer", &DMWRITE, addObjServicesVoiceServiceSIPNetworkFQDNServer, delObjServicesVoiceServiceSIPNetworkFQDNServer, NULL, NULL, NULL, NULL, NULL, NULL, tServicesVoiceServiceSIPNetworkFQDNServerParams, NULL, BBFDM_BOTH},
{"FQDNServer", &DMWRITE, addObjServicesVoiceServiceSIPNetworkFQDNServer, delObjServicesVoiceServiceSIPNetworkFQDNServer, NULL, browseServicesVoiceServiceSIPNetworkFQDNServerInst, NULL, NULL, NULL, NULL, tServicesVoiceServiceSIPNetworkFQDNServerParams, NULL, BBFDM_BOTH},
{0}
};

View file

@ -142,19 +142,33 @@ static int set_ServicesVoiceServiceVoIPProfileRTP_TelephoneEventPayloadType(char
/*#Device.Services.VoiceService.{i}.VoIPProfile.{i}.RTP.JitterBufferType!UCI:asterisk/tel_advanced,tel_options/jbimpl*/
static int get_ServicesVoiceServiceVoIPProfileRTP_JitterBufferType(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_option_value_string("asterisk", "tel_options", "jbimpl", value);
char *tmp = NULL;
dmuci_get_option_value_string("asterisk", "tel_options", "jbimpl", &tmp);
if (tmp && *tmp) {
if (strcasecmp(tmp, "adaptive") == 0)
*value = "Dynamic";
else
*value = "Static";
dmfree(tmp);
} else {
*value = "";
}
return 0;
}
static int set_ServicesVoiceServiceVoIPProfileRTP_JitterBufferType(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
char *uci_value = "fixed";
switch (action) {
case VALUECHECK:
if (dm_validate_string(value, -1, -1, JitterBufferType, 2, NULL, 0))
return FAULT_9007;
break;
case VALUESET:
dmuci_set_value("asterisk", "tel_options", "jbimpl", value);
if (strcasecmp(value, "Dynamic") == 0)
uci_value = "adaptive";
dmuci_set_value("asterisk", "tel_options", "jbimpl", uci_value);
break;
}
return 0;