Skip to content

Commit

Permalink
aaa_diameter: Rework exposing command results to script
Browse files Browse the repository at this point in the history
The initially exported value of Result-Code AVP integer value was not
ideal, as many Diameter exchanges are actual queries, with much more
rich data to be returned than just an integer code.

This commit replaces the "reply_code_pv" parameter of dm_send_request()
with "rpl_avps_pv", containing a JSON Array with all AVPs from the
Diameter Answer, as well as their values.
  • Loading branch information
liviuchircu committed May 27, 2022
1 parent 96d8113 commit 526394a
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 59 deletions.
2 changes: 1 addition & 1 deletion etc/dictionary.opensips
Expand Up @@ -23,7 +23,7 @@ ATTRIBUTE Sip-Call-Duration 227 integer
ATTRIBUTE Sip-Call-Setuptime 228 integer
ATTRIBUTE Sip-Call-Created 229 integer
ATTRIBUTE Sip-Call-MSDuration 230 integer
ATTRIBUTE Transaction-Id 231 string
ATTRIBUTE Transaction-Id 231 string # Proprietary, aaa_diameter

### Acct-Status-Type Values ###
VALUE Acct-Status-Type Start 1 # RFC2866, RADIUS acc
Expand Down
10 changes: 10 additions & 0 deletions lib/cJSON.c
Expand Up @@ -82,6 +82,16 @@ typedef int cjbool;

static const unsigned char *global_ep = NULL;

cJSON_Hooks sys_mem_hooks = {
.malloc_fn = malloc,
.free_fn = free,
};

cJSON_Hooks shm_mem_hooks = {
.malloc_fn = osips_shm_malloc,
.free_fn = osips_shm_free,
};

int cJSON_NumberIsInt(cJSON *item)
{
return ((FABS((double)item->valueint - item->valuedouble) <= DBL_EPSILON) &&
Expand Down
2 changes: 2 additions & 0 deletions lib/cJSON.h
Expand Up @@ -87,6 +87,8 @@ typedef int (flush_fn)(unsigned char *buf, int len, void *param);

/* Supply malloc, realloc and free functions to cJSON */
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
extern cJSON_Hooks sys_mem_hooks;
extern cJSON_Hooks shm_mem_hooks;


/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
Expand Down
9 changes: 0 additions & 9 deletions mi/mi.c
Expand Up @@ -46,15 +46,6 @@
static struct mi_cmd* mi_cmds = 0;
static int mi_cmds_no = 0;

static cJSON_Hooks sys_mem_hooks = {
.malloc_fn = malloc,
.free_fn = free,
};
static cJSON_Hooks shm_mem_hooks = {
.malloc_fn = osips_shm_malloc,
.free_fn = osips_shm_free,
};

void _init_mi_sys_mem_hooks(void)
{
cJSON_InitHooks(&sys_mem_hooks);
Expand Down
29 changes: 14 additions & 15 deletions modules/aaa_diameter/aaa_diameter.c
Expand Up @@ -36,7 +36,7 @@ char *dm_conf_filename = "freeDiameter.conf";
char *extra_avps_file;

static int dm_send_request(struct sip_msg *msg, int *app_id, int *cmd_code,
str *avp_json, pv_spec_t *res_code_pv);
str *avp_json, pv_spec_t *rpl_avps_pv);
static int dm_bind_api(aaa_prot *api);

int fd_log_level = FD_LOG_NOTICE;
Expand Down Expand Up @@ -201,12 +201,13 @@ static int dm_bind_api(aaa_prot *api)


static int dm_send_request(struct sip_msg *msg, int *app_id, int *cmd_code,
str *avp_json, pv_spec_t *res_code_pv)
str *avp_json, pv_spec_t *rpl_avps_pv)
{
aaa_message *dmsg = NULL;
struct dict_object *req;
cJSON *avps, *_avp;
int rc, res_code;
int rc;
char *rpl_avps;

if (fd_dict_search(fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_CODE_R,
cmd_code, &req, ENOENT) == ENOENT) {
Expand Down Expand Up @@ -308,17 +309,16 @@ static int dm_send_request(struct sip_msg *msg, int *app_id, int *cmd_code,
}
}

rc = _dm_send_message(NULL, dmsg, NULL, &res_code);
rc = _dm_send_message(NULL, dmsg, NULL, &rpl_avps);

if (res_code_pv) {
pv_value_t val = {STR_NULL, 0, PV_VAL_INT|PV_TYPE_INT};
val.ri = res_code;
if (pv_set_value(msg, res_code_pv, 0, &val) != 0)
LM_ERR("failed to set output res_code pv to %d\n", res_code);
if (rpl_avps_pv && rpl_avps) {
pv_value_t val = {(str){rpl_avps, strlen(rpl_avps)}, 0, PV_VAL_STR};
if (pv_set_value(msg, rpl_avps_pv, 0, &val) != 0)
LM_ERR("failed to set output rpl_avps pv to: %s\n", rpl_avps);
}

if (rc != 0) {
LM_ERR("Diameter request failed, Result-Code: %d\n", res_code);
LM_ERR("Diameter request failed\n");
cJSON_Delete(avps);
return rc;
}
Expand All @@ -327,11 +327,10 @@ static int dm_send_request(struct sip_msg *msg, int *app_id, int *cmd_code,
return 1;

error:
if (res_code_pv) {
pv_value_t val = {STR_NULL, 0, PV_VAL_INT|PV_TYPE_INT};
val.ri = -1;
if (pv_set_value(msg, res_code_pv, 0, &val) != 0)
LM_ERR("failed to set output res_code pv to %d\n", res_code);
if (rpl_avps_pv) {
pv_value_t val = {STR_NULL, 0, PV_VAL_NULL};
if (pv_set_value(msg, rpl_avps_pv, 0, &val) != 0)
LM_ERR("failed to set output rpl_avps pv to NULL\n");
}

_dm_destroy_message(dmsg);
Expand Down
108 changes: 90 additions & 18 deletions modules/aaa_diameter/aaa_impl.c
Expand Up @@ -204,11 +204,12 @@ static int dm_auth_reply(struct msg **_msg, struct avp * avp, struct session * s

static int dm_custom_cmd_reply(struct msg **_msg, struct avp * avp, struct session * sess, void * data, enum disp_action * act)
{
cJSON *avps = NULL;
struct msg_hdr *hdr = NULL;
struct msg *msg = *_msg;
struct avp *a = NULL;
struct avp *a = NULL, *it = NULL;
struct avp_hdr * h = NULL;
int rc;
int rc, i = 0;
str tid;
struct dm_cond **prpl_cond, *rpl_cond;

Expand All @@ -219,20 +220,78 @@ static int dm_custom_cmd_reply(struct msg **_msg, struct avp * avp, struct sessi
goto out;
}

FD_CHECK(fd_msg_search_avp(msg, dm_dict.Result_Code, &a));
FD_CHECK(fd_msg_avp_hdr(a, &h));
rc = h->avp_value->u32;
cJSON_InitHooks(&shm_mem_hooks);
avps = cJSON_CreateArray();
if (!avps) {
LM_ERR("oom 1\n");
goto out;
}

FD_CHECK(fd_msg_search_avp(msg, dm_dict.Transaction_Id, &a));
FD_CHECK(fd_msg_avp_hdr(a, &h));
FD_CHECK_GT(fd_msg_browse(msg, MSG_BRW_FIRST_CHILD, &it, NULL));

LM_DBG("------------ AVP iteration ----------------\n");
while (it) {
cJSON *item, *val;
struct dict_object *obj;
struct dict_avp_data dm_avp;

FD_CHECK_GT(fd_msg_avp_hdr(it, &h));

FD_CHECK_GT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_CODE,
&h->avp_code, &obj, ENOENT));
FD_CHECK_GT(fd_dict_getval(obj, &dm_avp));

item = cJSON_CreateObject();
if (!item) {
LM_ERR("oom 2\n");
goto out;
}

/* FIXME: there has to be an API-ish way of detecting type, but this works for now */
if (h->avp_len >= 12 && h->avp_value->os.len == 0) {
/* Integer AVP */
LM_DBG("%d. got integer AVP %u, value: %d\n", i, h->avp_code, h->avp_value->i32);

val = cJSON_CreateNumber((double)h->avp_value->i64);
if (!val) {
cJSON_Delete(item);
LM_ERR("oom 3\n");
goto out;
}
} else {
/* Octetstring AVP */
LM_DBG("%d. got string AVP %u, value: %.*s %s\n", i, h->avp_code, (int)h->avp_value->os.len, h->avp_value->os.data, h->avp_value->os.data);

val = cJSON_CreateString((const char *)h->avp_value->os.data);
if (!val) {
cJSON_Delete(item);
LM_ERR("oom 3\n");
goto out;
}
}

cJSON_AddItemToObject(item, dm_avp.avp_name, val);
cJSON_AddItemToArray(avps, item);

FD_CHECK_GT(fd_msg_browse(it, MSG_BRW_NEXT, &it, NULL));
i++;
}
LM_DBG("------------ END AVP iteration ----------------\n");

rc = fd_msg_search_avp(msg, dm_dict.Transaction_Id, &a);
if (rc != 0) {
LM_WARN("Missing Transaction-Id AVP in Diameter Answer %d/%d\n",
hdr->msg_appl, hdr->msg_code);
goto out;
}

FD_CHECK_GT(fd_msg_avp_hdr(a, &h));
tid.s = (char *)h->avp_value->os.data;
tid.len = (int)h->avp_value->os.len;

LM_DBG("%d/%d reply %d, Transaction-Id: %.*s\n", hdr->msg_appl,
hdr->msg_code, rc, tid.len, tid.s);

FD_CHECK(fd_msg_search_avp(msg, dm_dict.Error_Message, &a));

prpl_cond = (struct dm_cond **)hash_find_key(pending_replies, tid);
if (!prpl_cond) {
LM_ERR("failed to match Transaction_Id %.*s to a pending request\n",
Expand All @@ -248,15 +307,23 @@ static int dm_custom_cmd_reply(struct msg **_msg, struct avp * avp, struct sessi
goto out;
}

rpl_cond->rc = rc;
if (rpl_cond->rpl_avps_json)
shm_free(rpl_cond->rpl_avps_json);
rpl_cond->rpl_avps_json = cJSON_PrintUnformatted(avps);

hash_remove_key(pending_replies, tid);

fd_msg_search_avp(msg, dm_dict.Error_Message, &a);
if (a) {
rpl_cond->is_error = 1;
FD_CHECK(fd_msg_avp_hdr(a, &h));
LM_DBG("transaction failed, rc: %d (%.*s)\n",
rc, (int)h->avp_value->os.len, h->avp_value->os.data);
rc = fd_msg_avp_hdr(a, &h);
if (rc != 0) {
pthread_mutex_unlock(&rpl_cond->mutex);
goto out;
}

LM_DBG("transaction failed (%.*s)\n",
(int)h->avp_value->os.len, h->avp_value->os.data);
} else {
rpl_cond->is_error = 0;
}
Expand All @@ -266,6 +333,9 @@ static int dm_custom_cmd_reply(struct msg **_msg, struct avp * avp, struct sessi
pthread_mutex_unlock(&rpl_cond->mutex);

out:
cJSON_Delete(avps);
cJSON_InitHooks(NULL);

FD_CHECK(fd_msg_free(msg));
*_msg = NULL;
return 0;
Expand Down Expand Up @@ -1313,7 +1383,7 @@ int dm_avp_add(aaa_conn *_, aaa_message *msg, aaa_map *avp, void *val,


int _dm_send_message(aaa_conn *_, aaa_message *req, aaa_message **reply,
int *res_code)
char **rpl_avps)
{
struct dm_message *dm;

Expand Down Expand Up @@ -1361,18 +1431,20 @@ int _dm_send_message(aaa_conn *_, aaa_message *req, aaa_message **reply,
"reply\n", rc, strerror(rc));
pthread_mutex_unlock(&my_reply_cond->mutex);

if (res_code)
*res_code = -1;
if (rpl_avps)
*rpl_avps = NULL;
return -2;
}

pthread_mutex_unlock(&my_reply_cond->mutex);

LM_DBG("reply received, Result-Code: %d (%s)\n", my_reply_cond->rc,
my_reply_cond->is_error ? "FAILURE" : "SUCCESS");
LM_DBG("AVPs: %s\n", my_reply_cond->rpl_avps_json);

if (rpl_avps)
*rpl_avps = my_reply_cond->rpl_avps_json;

if (res_code)
*res_code = my_reply_cond->rc;
if (my_reply_cond->is_error)
return -1;
}
Expand Down
18 changes: 17 additions & 1 deletion modules/aaa_diameter/aaa_impl.h
Expand Up @@ -38,6 +38,21 @@
__FD_CHECK((__call__), (__retok__), __ret__)
#define FD_CHECK(__call__) _FD_CHECK((__call__), 0)

#define __FD_CHECK_GT(__call__, __retok__, __goto__) \
do { \
int __ret__; \
__ret__ = (__call__); \
if (__ret__ > 0) \
__ret__ = -__ret__; \
if (__ret__ != (__retok__)) { \
LM_ERR("error in %s: %d\n", #__call__, __ret__); \
goto __goto__; \
} \
} while (0)
#define _FD_CHECK_GT(__call__, __retok__) \
__FD_CHECK_GT((__call__), (__retok__), out)
#define FD_CHECK_GT(__call__) _FD_CHECK_GT((__call__), 0)

#define FD_CHECK_dict_new(type, data, parent, ref) \
FD_CHECK(fd_dict_new(fd_g_config->cnf_dict, (type), \
(data), (parent), (ref)))
Expand Down Expand Up @@ -98,6 +113,7 @@ struct dm_cond {

int rc; /* the Diameter Result-Code AVP value */
int is_error;
char *rpl_avps_json; /* JSON with all reply AVPs and their values */
};
int init_mutex_cond(pthread_mutex_t *mutex, pthread_cond_t *cond);

Expand All @@ -122,7 +138,7 @@ int dm_avp_add(aaa_conn *_, aaa_message *msg, aaa_map *avp, void *val,
int val_length, int vendor);
int dm_send_message(aaa_conn *_, aaa_message *req, aaa_message **__);
int _dm_send_message(aaa_conn *_, aaa_message *req, aaa_message **reply,
int *res_code);
char **rpl_avps);
int dm_destroy_message(aaa_conn *con, aaa_message *msg);
void _dm_destroy_message(aaa_message *msg);

Expand Down
15 changes: 13 additions & 2 deletions modules/aaa_diameter/app_opensips/app_opensips.c
Expand Up @@ -249,16 +249,26 @@ static int acc_request( struct msg ** msg, struct avp * avp, struct session * se
fd_log_debug("Session: %.*s", (int)sl, s);

/* The AVPs that we copy in the answer */
CHECK_FCT( fd_msg_search_avp ( qry, dm_dict.Transaction_Id, &a) );
if (a) {
CHECK_FCT( fd_msg_avp_hdr( a, &h ) );
fd_log_debug("[ACC] Transaction-Id: %.*s",
h->avp_value->os.len, h->avp_value->os.data);
CHECK_FCT( fd_msg_avp_new ( dm_dict.Transaction_Id, 0, &a ) );
CHECK_FCT( fd_msg_avp_setvalue( a, h->avp_value ) );
CHECK_FCT( fd_msg_avp_add( ans, MSG_BRW_LAST_CHILD, a ) );
}

CHECK_FCT( fd_msg_search_avp ( qry, dm_dict.Accounting_Record_Type, &a) );
if (a) {
CHECK_FCT( fd_msg_avp_hdr( a, &h ) );
fd_log_debug("Accounting-Record-Type: %d (%s)", h->avp_value->u32,
fd_log_debug("Accounting-Record-Type: %d (%s) %d %p", h->avp_value->u32,
/* it would be better to search this in the dictionary, but it is only for debug, so ok */
(h->avp_value->u32 == 1) ? "EVENT_RECORD" :
(h->avp_value->u32 == 2) ? "START_RECORD" :
(h->avp_value->u32 == 3) ? "INTERIM_RECORD" :
(h->avp_value->u32 == 4) ? "STOP_RECORD" :
"<unknown value>"
"<unknown value>", h->avp_value->os.len, h->avp_value->os.data
);
CHECK_FCT( fd_msg_avp_new ( dm_dict.Accounting_Record_Type, 0, &a ) );
CHECK_FCT( fd_msg_avp_setvalue( a, h->avp_value ) );
Expand Down Expand Up @@ -715,6 +725,7 @@ static int os_entry(char *confstring)
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Accounting-Record-Type", &dm_dict.Accounting_Record_Type, ENOENT) );
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Acct-Session-Id", &dm_dict.Acct_Session_Id, ENOENT) );
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Event-Timestamp", &dm_dict.Event_Timestamp, ENOENT) );
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Transaction-Id", &dm_dict.Transaction_Id, ENOENT) );

CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Auth-Application-Id", &dm_dict.Auth_Application_Id, ENOENT) );
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Auth-Session-State", &dm_dict.Auth_Session_State, ENOENT) );
Expand Down

0 comments on commit 526394a

Please sign in to comment.