From: Naveen Albert Date: Thu, 21 Jul 2022 19:07:04 +0000 (+0000) Subject: res_pjsip_header_funcs: Add custom parameter support. X-Git-Tag: 18.16.0-rc1~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=91a12a5cd48113ae88e61b1c9c4e5862d21b335e;p=thirdparty%2Fasterisk.git res_pjsip_header_funcs: Add custom parameter support. Adds support for custom URI and header parameters in the From header in PJSIP. Parameters can be both set and read using this function. ASTERISK-30150 #close Change-Id: Ifb1bc3c512ad5f6faeaebd7817f004a2ecbd6428 --- diff --git a/doc/CHANGES-staging/res_pjsip_parameters.txt b/doc/CHANGES-staging/res_pjsip_parameters.txt new file mode 100644 index 0000000000..c95b43dedf --- /dev/null +++ b/doc/CHANGES-staging/res_pjsip_parameters.txt @@ -0,0 +1,5 @@ +Subject: res_pjsip_header_funcs + +The new PJSIP_HEADER_PARAM function now fully supports both +URI and header parameters. Both reading and writing +parameters are supported. diff --git a/res/res_pjsip_header_funcs.c b/res/res_pjsip_header_funcs.c index cca2b78636..8a60e36aad 100644 --- a/res/res_pjsip_header_funcs.c +++ b/res/res_pjsip_header_funcs.c @@ -5,6 +5,7 @@ * * George Joseph * José Lopes + * Naveen Albert * * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact @@ -250,7 +251,53 @@ PJSIP_HEADERS - + + + Get or set header/URI parameters on a PJSIP channel. + + + + Header in which parameter should be read or set. + Currently, the only supported header is From. + + + The type of parameter to get or set. + Default is header parameter. + + + Header parameter. + + + URI parameter. + + + + + Name of parameter. + + + + PJSIP_HEADER_PARAM allows you to read or set parameters in a SIP header on a + PJSIP channel. + Both URI parameters and header parameters can be read and set using + this function. URI parameters appear in the URI (inside the <> in the header) + while header parameters appear afterwards. + If you call PJSIP_HEADER_PARAM in a normal dialplan context you'll be + operating on the caller's (incoming) channel which + may not be what you want. To operate on the callee's (outgoing) + channel call PJSIP_HEADER_PARAM in a pre-dial handler. + + [handler] + exten => addheader,1,Set(PJSIP_HEADER_PARAM(From,uri,isup-oli)=27) + same => n,Return() + [somecontext] + exten => 1,1,Dial(PJSIP/${EXTEN},,b(handler^addheader^1)) + + + same => n,Set(value=${PJSIP_HEADER_PARAM(From,uri,isup-oli)}) + + + ***/ /*! \brief Linked list for accumulating headers */ @@ -996,6 +1043,223 @@ static struct ast_sip_session_supplement header_funcs_supplement = { .incoming_response = incoming_response, }; +enum param_type { + PARAMETER_HEADER, + PARAMETER_URI, +}; + +struct param_data { + struct ast_sip_channel_pvt *channel; + char *header_name; + char *param_name; + const char *param_value; /* Only used for write */ + enum param_type paramtype; + /* For read function only */ + char *buf; + size_t len; +}; + +static int read_param(void *obj) +{ + struct param_data *data = obj; + struct ast_sip_session *session = data->channel->session; + pj_str_t param_name; + + pjsip_fromto_hdr *dlg_info; + pjsip_name_addr *dlg_info_name_addr; + pjsip_sip_uri *dlg_info_uri; + pjsip_param *param; + size_t param_len; + + dlg_info = session->inv_session->dlg->remote.info; /* Remote dialog for incoming */ + dlg_info_name_addr = (pjsip_name_addr *) dlg_info->uri; + dlg_info_uri = pjsip_uri_get_uri(dlg_info_name_addr); + + pj_cstr(¶m_name, data->param_name); + + if (data->paramtype == PARAMETER_URI) { /* URI parameter */ + param = pjsip_param_find(&dlg_info_uri->other_param, ¶m_name); + } else { /* Header parameter */ + param = pjsip_param_find(&dlg_info->other_param, ¶m_name); + } + + if (!param) { + ast_debug(1, "No %s parameter found named %s\n", + data->paramtype == PARAMETER_URI ? "URI" : "header", data->param_name); + return -1; + } + + param_len = pj_strlen(¶m->value); + if (param_len >= data->len) { + ast_log(LOG_ERROR, "Buffer is too small for parameter value (%zu > %zu)\n", param_len, data->len); + return -1; + } + + ast_debug(2, "Successfully read %s parameter %s (length %zu)\n", + data->paramtype == PARAMETER_URI ? "URI" : "header", data->param_name, param_len); + ast_copy_string(data->buf, pj_strbuf(¶m->value), data->len); + data->buf[pj_strlen(¶m->value)] = '\0'; + + return 0; +} + +/*! + * \internal + * \brief Implements PJSIP_HEADER_PARAM 'add' by adding the specified parameter. + * \note Unlike add_header, we can't add parameters in the outgoing_request callback: that's too late. + * That's why we do it here and not in a callback. + */ +static int add_param(void *obj) +{ + struct param_data *data = obj; + struct ast_sip_session *session = data->channel->session; + pj_pool_t *pool = session->inv_session->dlg->pool; + + pjsip_fromto_hdr *dlg_info; + pjsip_name_addr *dlg_info_name_addr; + pjsip_sip_uri *dlg_info_uri; + + dlg_info = session->inv_session->dlg->local.info; /* Local for outgoing */ + dlg_info_name_addr = (pjsip_name_addr *) dlg_info->uri; + dlg_info_uri = pjsip_uri_get_uri(dlg_info_name_addr); + if (!PJSIP_URI_SCHEME_IS_SIP(dlg_info_uri) && !PJSIP_URI_SCHEME_IS_SIPS(dlg_info_uri)) { + ast_log(LOG_WARNING, "Non SIP/SIPS URI\n"); + return -1; + } + + ast_debug(1, "Adding custom %s param %s = %s\n", + data->paramtype == PARAMETER_URI ? "URI" : "header", data->param_name, data->param_value); + + /* This works the same as doing this in set_from_header in res_pjsip_session.c + * The way that this maps to pjproject is a little confusing. + * Say we have ;o1=foo;o2=bar + * p1 and p2 are URI parameters. + * (h1 and h2 are URI headers) + * o1 and o2 are header parameters (and don't have anything to do with the URI) + * In pjproject, other_param is used for adding all custom parameters. + * We use the URI for URI stuff, including URI parameters, and the header directly for header parameters. + */ + +#define param_add(pool, list, pname, pvalue) { \ + pjsip_param *param; \ + param = PJ_POOL_ALLOC_T(pool, pjsip_param); \ + pj_strdup2(pool, ¶m->name, pname); \ + pj_strdup2(pool, ¶m->value, pvalue); \ + pj_list_insert_before(list, param); \ +} + + if (data->paramtype == PARAMETER_URI) { /* URI parameter */ + param_add(pool, &dlg_info_uri->other_param, data->param_name, S_OR(data->param_value, "")); + } else { /* Header parameter */ + param_add(pool, &dlg_info->other_param, data->param_name, S_OR(data->param_value, "")); + } + + return 0; +} + +static int func_read_param(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len) +{ + struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL; + struct param_data param_data; + + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(header_name); + AST_APP_ARG(param_type); + AST_APP_ARG(param_name); + ); + + AST_STANDARD_APP_ARGS(args, data); + + param_data.channel = channel; + + if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) { + ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n"); + return -1; + } + if (ast_strlen_zero(args.param_type)) { + ast_log(AST_LOG_ERROR, "This function requires a parameter type.\n"); + return -1; + } + if (ast_strlen_zero(args.param_name)) { + ast_log(AST_LOG_ERROR, "This function requires a parameter name.\n"); + return -1; + } + + /* Currently, only From is supported, but this could be extended in the future. */ + if (ast_strlen_zero(args.header_name) || strcasecmp(args.header_name, "From")) { + ast_log(LOG_WARNING, "Only the From header is currently supported\n"); + return -1; + } + + param_data.param_name = args.param_name; + if (!strcasecmp(args.param_type, "header")) { + param_data.paramtype = PARAMETER_HEADER; + } else if (!strcasecmp(args.param_type, "uri")) { + param_data.paramtype = PARAMETER_URI; + } else { + ast_log(LOG_WARNING, "Parameter type '%s' is invalid: must be 'header' or 'uri'\n", args.param_type); + return -1; + } + + param_data.buf = buf; + param_data.len = len; + + return ast_sip_push_task_wait_serializer(channel->session->serializer, read_param, ¶m_data); +} + +static int func_write_param(struct ast_channel *chan, const char *cmd, char *data, const char *value) +{ + struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL; + struct param_data param_data; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(header_name); + AST_APP_ARG(param_type); + AST_APP_ARG(param_name); + ); + + AST_STANDARD_APP_ARGS(args, data); + + param_data.channel = channel; + + if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) { + ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n"); + return -1; + } + if (ast_strlen_zero(args.param_type)) { + ast_log(AST_LOG_ERROR, "This function requires a parameter type.\n"); + return -1; + } + if (ast_strlen_zero(args.param_name)) { + ast_log(AST_LOG_ERROR, "This function requires a parameter name.\n"); + return -1; + } + + /* Currently, only From is supported, but this could be extended in the future. */ + if (ast_strlen_zero(args.header_name) || strcasecmp(args.header_name, "From")) { + ast_log(LOG_WARNING, "Only the From header is currently supported\n"); + return -1; + } + + param_data.param_name = args.param_name; + if (!strcasecmp(args.param_type, "header")) { + param_data.paramtype = PARAMETER_HEADER; + } else if (!strcasecmp(args.param_type, "uri")) { + param_data.paramtype = PARAMETER_URI; + } else { + ast_log(LOG_WARNING, "Parameter type '%s' is invalid: must be 'header' or 'uri'\n", args.param_type); + return -1; + } + param_data.param_value = value; + + return ast_sip_push_task_wait_serializer(channel->session->serializer, add_param, ¶m_data); +} + +static struct ast_custom_function pjsip_header_param_function = { + .name = "PJSIP_HEADER_PARAM", + .read = func_read_param, + .write = func_write_param, +}; + static int load_module(void) { ast_sip_session_register_supplement(&header_funcs_supplement); @@ -1003,6 +1267,7 @@ static int load_module(void) ast_custom_function_register(&pjsip_headers_function); ast_custom_function_register(&pjsip_response_header_function); ast_custom_function_register(&pjsip_response_headers_function); + ast_custom_function_register(&pjsip_header_param_function); return AST_MODULE_LOAD_SUCCESS; } @@ -1013,6 +1278,7 @@ static int unload_module(void) ast_custom_function_unregister(&pjsip_headers_function); ast_custom_function_unregister(&pjsip_response_header_function); ast_custom_function_unregister(&pjsip_response_headers_function); + ast_custom_function_unregister(&pjsip_header_param_function); ast_sip_session_unregister_supplement(&header_funcs_supplement); return 0; }