Asterisk - The Open Source Telephony Project GIT-master-27fb039
Loading...
Searching...
No Matches
Data Structures | Functions | Variables
res_pjsip_aoc.c File Reference
#include "asterisk.h"
#include <pjsip.h>
#include <pjlib.h>
#include "asterisk/aoc.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/res_pjsip.h"
#include "asterisk/res_pjsip_session.h"
Include dependency graph for res_pjsip_aoc.c:

Go to the source code of this file.

Data Structures

struct  aoc_data
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static void aoc_attach_framehook (struct ast_sip_session *session)
 
static void aoc_bye_outgoing_request (struct ast_sip_session *session, struct pjsip_tx_data *tdata)
 
static void aoc_bye_outgoing_response (struct ast_sip_session *session, struct pjsip_tx_data *tdata)
 
static int aoc_consume (void *data, enum ast_frame_type type)
 
static void aoc_data_destroy (void *data)
 
static void aoc_datastore_destroy (void *obj)
 
static char * aoc_format_amount (pj_pool_t *pool, unsigned int amount, enum ast_aoc_currency_multiplier multiplier)
 
static struct ast_frameaoc_framehook (struct ast_channel *ast, struct ast_frame *f, enum ast_framehook_event event, void *data)
 
static int aoc_incoming_invite_request (struct ast_sip_session *session, struct pjsip_rx_data *rdata)
 
static void aoc_invite_outgoing_response (struct ast_sip_session *session, struct pjsip_tx_data *tdata)
 
static void aoc_outgoing_invite_request (struct ast_sip_session *session, struct pjsip_tx_data *tdata)
 
static void aoc_release_pool (void *data)
 
static int aoc_send_as_xml (void *data)
 
static const char * aoc_time_scale_str (enum ast_aoc_time_scale value)
 
static pj_xml_attr * aoc_xml_create_attr (pj_pool_t *pool, pj_xml_node *node, const char *name, const char *value)
 
static pj_xml_node * aoc_xml_create_node (pj_pool_t *pool, pj_xml_node *parent, const char *name)
 
static void aoc_xml_set_node_content (pj_pool_t *pool, pj_xml_node *node, const char *content)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int load_module (void)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP AOC Support" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, .requires = "res_pjsip", }
 
static struct ast_sip_session_supplement aoc_bye_supplement
 
static const struct ast_datastore_info aoc_d_datastore
 
static const struct ast_datastore_info aoc_e_datastore
 
static struct ast_sip_session_supplement aoc_invite_supplement
 
static const struct ast_datastore_info aoc_s_datastore
 
static const struct ast_module_infoast_module_info = &__mod_info
 

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 698 of file res_pjsip_aoc.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 698 of file res_pjsip_aoc.c.

◆ aoc_attach_framehook()

static void aoc_attach_framehook ( struct ast_sip_session session)
static

Definition at line 522 of file res_pjsip_aoc.c.

523{
524 int framehook_id;
525 static struct ast_framehook_interface hook = {
527 .event_cb = aoc_framehook,
528 .consume_cb = aoc_consume,
529 };
530
531 if (!session->channel || !session->endpoint->send_aoc) {
532 return;
533 }
534
535 ast_channel_lock(session->channel);
536
537 framehook_id = ast_framehook_attach(session->channel, &hook);
538 if (framehook_id < 0) {
539 ast_log(LOG_WARNING, "Could not attach AOC Frame hook, AOC will be unavailable on '%s'\n",
540 ast_channel_name(session->channel));
541 }
542
543 ast_channel_unlock(session->channel);
544}
static struct ast_mansession session
#define ast_log
Definition astobj2.c:42
const char * ast_channel_name(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition channel.h:2982
#define ast_channel_unlock(chan)
Definition channel.h:2983
int ast_framehook_attach(struct ast_channel *chan, struct ast_framehook_interface *i)
Attach an framehook onto a channel for frame interception.
Definition framehook.c:132
#define AST_FRAMEHOOK_INTERFACE_VERSION
Definition framehook.h:227
#define LOG_WARNING
static int aoc_consume(void *data, enum ast_frame_type type)
static struct ast_frame * aoc_framehook(struct ast_channel *ast, struct ast_frame *f, enum ast_framehook_event event, void *data)

References aoc_consume(), aoc_framehook(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_framehook_attach(), AST_FRAMEHOOK_INTERFACE_VERSION, ast_log, LOG_WARNING, session, and ast_framehook_interface::version.

Referenced by aoc_incoming_invite_request(), and aoc_outgoing_invite_request().

◆ aoc_bye_outgoing_request()

static void aoc_bye_outgoing_request ( struct ast_sip_session session,
struct pjsip_tx_data *  tdata 
)
static

Definition at line 585 of file res_pjsip_aoc.c.

587{
588 struct ast_sip_body body = {
589 .type = "application",
590 .subtype = "vnd.etsi.aoc+xml",
591 };
596
597 if (datastore_e) {
598 body.body_text = datastore_e->data;
599 } else if (datastore_d) {
600 body.body_text = datastore_d->data;
601 }
602 else {
603 return;
604 }
605
606 if (ast_sip_add_body(tdata, &body)) {
607 ast_log(LOG_ERROR, "Could not add body to AOC INFO request\n");
608 }
609}
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define LOG_ERROR
int ast_sip_add_body(pjsip_tx_data *tdata, const struct ast_sip_body *body)
Add a body to an outbound SIP message.
Definition res_pjsip.c:2052
static const struct ast_datastore_info aoc_e_datastore
static const struct ast_datastore_info aoc_d_datastore
struct ast_datastore * ast_sip_session_get_datastore(struct ast_sip_session *session, const char *name)
Retrieve a session datastore.
const char * type
Definition datastore.h:32
Structure for a data store object.
Definition datastore.h:64
SIP body description.
Definition res_pjsip.h:2444
const char * type
Definition res_pjsip.h:2446
const char * body_text
Definition res_pjsip.h:2450
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981

References ao2_cleanup, aoc_d_datastore, aoc_e_datastore, ast_log, ast_sip_add_body(), ast_sip_session_get_datastore(), ast_sip_body::body_text, LOG_ERROR, RAII_VAR, session, ast_datastore_info::type, and ast_sip_body::type.

◆ aoc_bye_outgoing_response()

static void aoc_bye_outgoing_response ( struct ast_sip_session session,
struct pjsip_tx_data *  tdata 
)
static

Definition at line 559 of file res_pjsip_aoc.c.

561{
562 struct ast_sip_body body = {
563 .type = "application",
564 .subtype = "vnd.etsi.aoc+xml",
565 };
570
571 if (datastore_e) {
572 body.body_text = datastore_e->data;
573 } else if (datastore_d) {
574 body.body_text = datastore_d->data;
575 }
576 else {
577 return;
578 }
579
580 if (ast_sip_add_body(tdata, &body)) {
581 ast_log(LOG_ERROR, "Could not add body to AOC INFO request\n");
582 }
583}

References ao2_cleanup, aoc_d_datastore, aoc_e_datastore, ast_log, ast_sip_add_body(), ast_sip_session_get_datastore(), ast_sip_body::body_text, LOG_ERROR, RAII_VAR, session, ast_datastore_info::type, and ast_sip_body::type.

◆ aoc_consume()

static int aoc_consume ( void *  data,
enum ast_frame_type  type 
)
static

Definition at line 517 of file res_pjsip_aoc.c.

518{
519 return (type == AST_FRAME_CONTROL) ? 1 : 0;
520}
static const char type[]
@ AST_FRAME_CONTROL

References AST_FRAME_CONTROL, and type.

Referenced by aoc_attach_framehook().

◆ aoc_data_destroy()

static void aoc_data_destroy ( void *  data)
static

Definition at line 474 of file res_pjsip_aoc.c.

475{
476 struct aoc_data *adata = data;
477
479 ao2_cleanup(adata->session);
480}
void * ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
free an ast_aoc_decoded object
Definition aoc.c:316
struct ast_sip_session * session
struct ast_aoc_decoded * decoded

References ao2_cleanup, ast_aoc_destroy_decoded(), aoc_data::decoded, and aoc_data::session.

Referenced by aoc_framehook().

◆ aoc_datastore_destroy()

static void aoc_datastore_destroy ( void *  obj)
static

Definition at line 143 of file res_pjsip_aoc.c.

144{
145 char *xml = obj;
146 ast_free(xml);
147}
#define ast_free(a)
Definition astmm.h:180

References ast_free.

◆ aoc_format_amount()

static char * aoc_format_amount ( pj_pool_t *  pool,
unsigned int  amount,
enum ast_aoc_currency_multiplier  multiplier 
)
static

Definition at line 75 of file res_pjsip_aoc.c.

77{
78 const size_t amount_max_size = 16;
79 char *amount_str;
80
81 amount_str = pj_pool_alloc(pool, amount_max_size);
82
83 switch (multiplier) {
85 pj_ansi_snprintf(amount_str, amount_max_size, "%.3f", amount*0.001f);
86 break;
88 pj_ansi_snprintf(amount_str, amount_max_size, "%.2f", amount*0.01f);
89 break;
91 pj_ansi_snprintf(amount_str, amount_max_size, "%.1f", amount*0.1f);
92 break;
94 pj_ansi_snprintf(amount_str, amount_max_size, "%d", amount);
95 break;
97 pj_ansi_snprintf(amount_str, amount_max_size, "%d", amount*10);
98 break;
100 pj_ansi_snprintf(amount_str, amount_max_size, "%d", amount*100);
101 break;
103 pj_ansi_snprintf(amount_str, amount_max_size, "%d", amount*1000);
104 break;
105 default:
106 pj_ansi_snprintf(amount_str, amount_max_size, "%d", amount);
107 }
108
109 return amount_str;
110}
@ AST_AOC_MULT_TEN
Definition aoc.h:39
@ AST_AOC_MULT_ONEHUNDREDTH
Definition aoc.h:36
@ AST_AOC_MULT_HUNDRED
Definition aoc.h:40
@ AST_AOC_MULT_ONETENTH
Definition aoc.h:37
@ AST_AOC_MULT_ONETHOUSANDTH
Definition aoc.h:35
@ AST_AOC_MULT_THOUSAND
Definition aoc.h:41
@ AST_AOC_MULT_ONE
Definition aoc.h:38

References AST_AOC_MULT_HUNDRED, AST_AOC_MULT_ONE, AST_AOC_MULT_ONEHUNDREDTH, AST_AOC_MULT_ONETENTH, AST_AOC_MULT_ONETHOUSANDTH, AST_AOC_MULT_TEN, and AST_AOC_MULT_THOUSAND.

Referenced by aoc_send_as_xml().

◆ aoc_framehook()

static struct ast_frame * aoc_framehook ( struct ast_channel ast,
struct ast_frame f,
enum ast_framehook_event  event,
void *  data 
)
static

Definition at line 482 of file res_pjsip_aoc.c.

484{
485 struct ast_sip_channel_pvt *channel;
486 struct aoc_data *adata;
487
490 return f;
491 }
492
493 adata = ao2_alloc(sizeof(struct aoc_data), aoc_data_destroy);
494 if (!adata) {
495 ast_log(LOG_ERROR, "Failed to allocate AOC data\n");
496 return f;
497 }
498
499 adata->decoded = ast_aoc_decode((struct ast_aoc_encoded *) f->data.ptr, f->datalen, ast);
500 if (!adata->decoded) {
501 ast_log(LOG_ERROR, "Error decoding indicated AOC data\n");
502 ao2_ref(adata, -1);
503 return f;
504 }
505
506 channel = ast_channel_tech_pvt(ast);
507 adata->session = ao2_bump(channel->session);
508 adata->channel_state = ast_channel_state(ast);
509
511 ast_log(LOG_ERROR, "Unable to send AOC XML for channel %s\n", ast_channel_name(ast));
512 ao2_ref(adata, -1);
513 }
514 return &ast_null_frame;
515}
struct ast_aoc_decoded * ast_aoc_decode(struct ast_aoc_encoded *encoded, size_t size, struct ast_channel *chan)
decodes an encoded aoc payload.
Definition aoc.c:458
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
void * ast_channel_tech_pvt(const struct ast_channel *chan)
ast_channel_state
ast_channel states
@ AST_FRAMEHOOK_EVENT_WRITE
Definition framehook.h:153
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition res_pjsip.c:2099
struct ast_frame ast_null_frame
Definition main/frame.c:79
static void aoc_data_destroy(void *data)
static int aoc_send_as_xml(void *data)
enum ast_channel_state channel_state
struct ast_frame_subclass subclass
enum ast_frame_type frametype
union ast_frame::@239 data
A structure which contains a channel implementation and session.
struct ast_sip_session * session
Pointer to session.
struct ast_taskprocessor * serializer

References ao2_alloc, ao2_bump, ao2_ref, aoc_data_destroy(), aoc_send_as_xml(), ast_aoc_decode(), ast_channel_name(), ast_channel_tech_pvt(), AST_CONTROL_AOC, AST_FRAME_CONTROL, AST_FRAMEHOOK_EVENT_WRITE, ast_log, ast_null_frame, ast_sip_push_task(), aoc_data::channel_state, ast_frame::data, ast_frame::datalen, aoc_data::decoded, ast_frame::frametype, ast_frame_subclass::integer, LOG_ERROR, ast_frame::ptr, ast_sip_session::serializer, ast_sip_channel_pvt::session, aoc_data::session, and ast_frame::subclass.

Referenced by aoc_attach_framehook().

◆ aoc_incoming_invite_request()

static int aoc_incoming_invite_request ( struct ast_sip_session session,
struct pjsip_rx_data *  rdata 
)
static

Definition at line 546 of file res_pjsip_aoc.c.

548{
550 return 0;
551}
static void aoc_attach_framehook(struct ast_sip_session *session)

References aoc_attach_framehook(), and session.

◆ aoc_invite_outgoing_response()

static void aoc_invite_outgoing_response ( struct ast_sip_session session,
struct pjsip_tx_data *  tdata 
)
static

Definition at line 611 of file res_pjsip_aoc.c.

613{
614 pjsip_msg_body *multipart_body;
615 pjsip_multipart_part *part;
616 pj_str_t body_text;
617 pj_str_t type;
618 pj_str_t subtype;
621
622 if (tdata->msg->line.status.code != 180 && tdata->msg->line.status.code != 183 &&
623 tdata->msg->line.status.code != 200) {
624 return;
625 }
626
627 if (!datastore) {
628 return;
629 }
630
631 if (tdata->msg->body && pjsip_media_type_cmp(&tdata->msg->body->content_type,
633 multipart_body = tdata->msg->body;
634 } else {
635 pjsip_sdp_info *tdata_sdp_info;
636
637 tdata_sdp_info = pjsip_tdata_get_sdp_info(tdata);
638 if (tdata_sdp_info->sdp) {
639 pj_status_t rc;
640
641 rc = pjsip_create_multipart_sdp_body(tdata->pool, tdata_sdp_info->sdp,
642 &multipart_body);
643 if (rc != PJ_SUCCESS) {
644 ast_log(LOG_ERROR, "Unable to create sdp multipart body\n");
645 return;
646 }
647 } else {
648 multipart_body = pjsip_multipart_create(tdata->pool,
650 }
651 }
652
653 part = pjsip_multipart_create_part(tdata->pool);
654 pj_strdup2(tdata->pool, &body_text, datastore->data);
655 pj_cstr(&type, "application");
656 pj_cstr(&subtype, "vnd.etsi.aoc+xml");
657 part->body = pjsip_msg_body_create(tdata->pool, &type, &subtype, &body_text);
658 pjsip_multipart_add_part(tdata->pool, multipart_body, part);
659
660 tdata->msg->body = multipart_body;
661}
pjsip_media_type pjsip_media_type_multipart_mixed
Definition res_pjsip.c:3918
static const struct ast_datastore_info aoc_s_datastore
#define NULL
Definition resample.c:96

References ao2_cleanup, aoc_s_datastore, ast_log, ast_sip_session_get_datastore(), ast_sip_body::body_text, LOG_ERROR, NULL, pjsip_media_type_multipart_mixed, RAII_VAR, session, ast_sip_body::subtype, type, and ast_datastore_info::type.

◆ aoc_outgoing_invite_request()

static void aoc_outgoing_invite_request ( struct ast_sip_session session,
struct pjsip_tx_data *  tdata 
)
static

Definition at line 553 of file res_pjsip_aoc.c.

555{
557}

References aoc_attach_framehook(), and session.

◆ aoc_release_pool()

static void aoc_release_pool ( void *  data)
static

Definition at line 170 of file res_pjsip_aoc.c.

171{
172 pj_pool_t *pool = data;
173 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
174}
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition res_pjsip.c:520

References ast_sip_get_pjsip_endpoint().

Referenced by aoc_send_as_xml().

◆ aoc_send_as_xml()

static int aoc_send_as_xml ( void *  data)
static

Definition at line 176 of file res_pjsip_aoc.c.

177{
178 RAII_VAR(struct aoc_data *, adata, data, ao2_cleanup);
179 RAII_VAR(pj_pool_t *, pool, NULL, aoc_release_pool);
180
181 pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "AOC", 2048, 512);
182
183 if (!pool) {
184 ast_log(LOG_ERROR, "Could not create a memory pool for AOC XML\n");
185 return 1;
186 }
187
188 if (ast_aoc_get_msg_type(adata->decoded) == AST_AOC_D ||
189 ast_aoc_get_msg_type(adata->decoded) == AST_AOC_E) {
190 pj_xml_node *aoc;
191 pj_xml_node *aoc_type;
192 pj_xml_node *charging_info = NULL;
193 pj_xml_node *charges;
194 pj_xml_node *charge;
195 char *xml;
196 size_t size;
197 const size_t xml_max_size = 512;
198
199 aoc = aoc_xml_create_node(pool, NULL, "aoc");
200 aoc_xml_create_attr(pool, aoc, "xmlns",
201 "http://uri.etsi.org/ngn/params/xml/simservs/aoc");
202 aoc_type = aoc_xml_create_node(pool, aoc,
203 ast_aoc_get_msg_type(adata->decoded) == AST_AOC_D ? "aoc-d" : "aoc-e");
204 if (ast_aoc_get_msg_type(adata->decoded) == AST_AOC_D) {
205 charging_info = aoc_xml_create_node(pool, aoc_type, "charging-info");
206 aoc_xml_set_node_content(pool, charging_info,
207 ast_aoc_get_total_type(adata->decoded) == AST_AOC_SUBTOTAL ? "subtotal" : "total");
208 }
209 charges = aoc_xml_create_node(pool, aoc_type, "recorded-charges");
210
211 if (ast_aoc_get_charge_type(adata->decoded) == AST_AOC_CHARGE_FREE) {
212 charge = aoc_xml_create_node(pool, charges, "free-charge");
213 } else if (ast_aoc_get_charge_type(adata->decoded) == AST_AOC_CHARGE_CURRENCY ||
214 ast_aoc_get_charge_type(adata->decoded) == AST_AOC_CHARGE_UNIT) {
215 charge = aoc_xml_create_node(pool, charges, "recorded-currency-units");
216 } else {
217 charge = aoc_xml_create_node(pool, charges, "not-available");
218 }
219
220 if (ast_aoc_get_charge_type(adata->decoded) == AST_AOC_CHARGE_CURRENCY) {
221 const char *currency;
222 pj_xml_node *amount;
223 char *amount_str;
224
225 currency = ast_aoc_get_currency_name(adata->decoded);
226 if (!ast_strlen_zero(currency)) {
227 pj_xml_node *currency_id;
228
229 currency_id = aoc_xml_create_node(pool, charge, "currency-id");
230 aoc_xml_set_node_content(pool, currency_id, currency);
231 }
232
233 amount = aoc_xml_create_node(pool, charge, "currency-amount");
234 amount_str = aoc_format_amount(pool, ast_aoc_get_currency_amount(adata->decoded),
235 ast_aoc_get_currency_multiplier(adata->decoded));
236 aoc_xml_set_node_content(pool, amount, amount_str);
237 } else if (ast_aoc_get_charge_type(adata->decoded) == AST_AOC_CHARGE_UNIT) {
238 pj_xml_node *currency_id;
239 const struct ast_aoc_unit_entry *unit_entry;
240
241 currency_id = aoc_xml_create_node(pool, charge, "currency-id");
242 aoc_xml_set_node_content(pool, currency_id, "UNIT");
243
244 unit_entry = ast_aoc_get_unit_info(adata->decoded, 0);
245 if (unit_entry) {
246 pj_xml_node *amount;
247 char *amount_str;
248
249 amount = aoc_xml_create_node(pool, charge, "currency-amount");
250 amount_str = aoc_format_amount(pool, unit_entry->amount,
252 aoc_xml_set_node_content(pool, amount, amount_str);
253 }
254 }
255
256 xml = pj_pool_alloc(pool, xml_max_size);
257 size = pj_xml_print(aoc, xml, xml_max_size - 1, PJ_TRUE);
258 if (size >= xml_max_size) {
259 ast_log(LOG_ERROR, "aoc+xml body text too large\n");
260 return 1;
261 }
262 xml[size] = 0;
263
264 if (ast_aoc_get_msg_type(adata->decoded) == AST_AOC_D) {
265 RAII_VAR(struct ast_datastore *, datastore,
268 struct pjsip_tx_data *tdata;
269 struct ast_sip_body body = {
270 .type = "application",
271 .subtype = "vnd.etsi.aoc+xml",
272 .body_text = xml
273 };
274
275 if (ast_sip_create_request("INFO", adata->session->inv_session->dlg,
276 adata->session->endpoint, NULL, NULL, &tdata)) {
277 ast_log(LOG_ERROR, "Could not create AOC INFO request\n");
278 return 1;
279 }
280 if (ast_sip_add_body(tdata, &body)) {
281 ast_log(LOG_ERROR, "Could not add body to AOC INFO request\n");
282 pjsip_tx_data_dec_ref(tdata);
283 return 1;
284 }
285 ast_sip_session_send_request(adata->session, tdata);
286
287 if (!datastore) {
289 if (!datastore) {
290 ast_log(LOG_ERROR, "Unable to create datastore for AOC-D.\n");
291 return 1;
292 }
293 datastore->data = NULL;
294 if (ast_sip_session_add_datastore(adata->session, datastore)) {
295 ast_log(LOG_ERROR, "Unable to create datastore for AOC-D.\n");
296 return 1;
297 }
298 } else {
299 ast_free(datastore->data);
300 }
301
302 aoc_xml_set_node_content(pool, charging_info, "total");
303 size = pj_xml_print(aoc, xml, xml_max_size - 1, PJ_TRUE);
304 xml[size] = 0;
305 datastore->data = ast_strdup(xml);
306 } else if (ast_aoc_get_msg_type(adata->decoded) == AST_AOC_E) {
307 RAII_VAR(struct ast_datastore *, datastore,
310 if (!datastore) {
312 if (!datastore) {
313 ast_log(LOG_ERROR, "Unable to create datastore for AOC-E.\n");
314 return 1;
315 }
316 datastore->data = NULL;
317 if (ast_sip_session_add_datastore(adata->session, datastore)) {
318 ast_log(LOG_ERROR, "Unable to create datastore for AOC-E.\n");
319 return 1;
320 }
321 } else {
322 ast_free(datastore->data);
323 }
324 datastore->data = ast_strdup(xml);
325 }
326 } else if (ast_aoc_get_msg_type(adata->decoded) == AST_AOC_S) {
327 pj_xml_node *aoc;
328 pj_xml_node *aoc_type;
329 pj_xml_node *charged_items;
330 const struct ast_aoc_s_entry *entry;
331 int idx;
332 char *xml;
333 size_t size;
334 const size_t xml_max_size = 1024;
335
336 aoc = aoc_xml_create_node(pool, NULL, "aoc");
337 aoc_xml_create_attr(pool, aoc, "xmlns",
338 "http://uri.etsi.org/ngn/params/xml/simservs/aoc");
339 aoc_type = aoc_xml_create_node(pool, aoc, "aoc-s");
340 charged_items = aoc_xml_create_node(pool, aoc_type, "charged-items");
341
342 for (idx = 0; idx < ast_aoc_s_get_count(adata->decoded); idx++) {
343 pj_xml_node *charged_item;
344 pj_xml_node *charge;
345
346 if (!(entry = ast_aoc_s_get_rate_info(adata->decoded, idx))) {
347 break;
348 }
349
351 charged_item = aoc_xml_create_node(pool, charged_items, "basic");
352 } else if (entry->charged_item == AST_AOC_CHARGED_ITEM_CALL_ATTEMPT) {
353 charged_item = aoc_xml_create_node(pool, charged_items,
354 "communication-attempt");
355 } else if (entry->charged_item == AST_AOC_CHARGED_ITEM_CALL_SETUP) {
356 charged_item = aoc_xml_create_node(pool, charged_items,
357 "communication-setup");
358 } else {
359 continue;
360 }
361
362 if (entry->rate_type == AST_AOC_RATE_TYPE_FREE) {
363 charge = aoc_xml_create_node(pool, charged_item, "free-charge");
364 } else if (entry->rate_type == AST_AOC_RATE_TYPE_FLAT) {
365 charge = aoc_xml_create_node(pool, charged_item, "flat-rate");
366 } else if (entry->rate_type == AST_AOC_RATE_TYPE_DURATION &&
368 charge = aoc_xml_create_node(pool, charged_item, "price-time");
369 } else {
370 continue;
371 }
372
375 const char *currency;
376 pj_xml_node *amount;
377 uint32_t amount_val;
378 enum ast_aoc_currency_multiplier multiplier_val;
379 char *amount_str;
380
381 currency = (entry->rate_type == AST_AOC_RATE_TYPE_DURATION ?
383 entry->rate.flat.currency_name);
384 if (!ast_strlen_zero(currency)) {
385 pj_xml_node *currency_id;
386
387 currency_id = aoc_xml_create_node(pool, charge, "currency-id");
388 aoc_xml_set_node_content(pool, currency_id, currency);
389 }
390
391 amount = aoc_xml_create_node(pool, charge, "currency-amount");
392 amount_val = (entry->rate_type == AST_AOC_RATE_TYPE_DURATION ?
393 entry->rate.duration.amount : entry->rate.flat.amount);
394 multiplier_val = (entry->rate_type == AST_AOC_RATE_TYPE_DURATION ?
395 entry->rate.duration.multiplier : entry->rate.flat.multiplier);
396 amount_str = aoc_format_amount(pool, amount_val, multiplier_val);
397 aoc_xml_set_node_content(pool, amount, amount_str);
398 }
399
401 pj_xml_node *length_time_unit;
402 pj_xml_node *time_unit;
403 char *time_str;
404 pj_xml_node *scale;
405 pj_xml_node *charging_type;
406
407 length_time_unit = aoc_xml_create_node(pool, charge, "length-time-unit");
408 time_unit = aoc_xml_create_node(pool, length_time_unit, "time-unit");
409 time_str = aoc_format_amount(pool, entry->rate.duration.time,
411 aoc_xml_set_node_content(pool, time_unit, time_str);
412 scale = aoc_xml_create_node(pool, length_time_unit, "scale");
413 aoc_xml_set_node_content(pool, scale,
415 charging_type = aoc_xml_create_node(pool, charge, "charging-type");
416 aoc_xml_set_node_content(pool, charging_type,
417 entry->rate.duration.charging_type ? "step-function" :
418 "continuous");
419 }
420 }
421
422 xml = pj_pool_alloc(pool, xml_max_size);
423 size = pj_xml_print(aoc, xml, xml_max_size - 1, PJ_TRUE);
424 if (size >= xml_max_size) {
425 ast_log(LOG_ERROR, "aoc+xml body text too large\n");
426 return 1;
427 }
428 xml[size] = 0;
429
430 if (adata->channel_state == AST_STATE_UP ||
431 adata->session->call_direction == AST_SIP_SESSION_OUTGOING_CALL) {
432 struct pjsip_tx_data *tdata;
433 struct ast_sip_body body = {
434 .type = "application",
435 .subtype = "vnd.etsi.aoc+xml",
436 .body_text = xml
437 };
438
439 if (ast_sip_create_request("INFO", adata->session->inv_session->dlg,
440 adata->session->endpoint, NULL, NULL, &tdata)) {
441 ast_log(LOG_ERROR, "Could not create AOC INFO request\n");
442 return 1;
443 }
444 if (ast_sip_add_body(tdata, &body)) {
445 ast_log(LOG_ERROR, "Could not add body to AOC INFO request\n");
446 pjsip_tx_data_dec_ref(tdata);
447 return 1;
448 }
449 ast_sip_session_send_request(adata->session, tdata);
450 } else {
451 RAII_VAR(struct ast_datastore *, datastore,
454 if (!datastore) {
456 if (!datastore) {
457 ast_log(LOG_ERROR, "Unable to create datastore for AOC-S.\n");
458 return 1;
459 }
460 if (ast_sip_session_add_datastore(adata->session, datastore)) {
461 ast_log(LOG_ERROR, "Unable to create datastore for AOC-S.\n");
462 return 1;
463 }
464 } else {
465 ast_free(datastore->data);
466 }
467 datastore->data = ast_strdup(xml);
468 }
469 }
470
471 return 0;
472}
enum ast_aoc_total_type ast_aoc_get_total_type(struct ast_aoc_decoded *decoded)
get the type of total for a AOC-D message
Definition aoc.c:923
const char * ast_aoc_get_currency_name(struct ast_aoc_decoded *decoded)
get the currency name for AOC-D and AOC-E messages
Definition aoc.c:981
@ AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION
Definition aoc.h:148
@ AST_AOC_CHARGED_ITEM_CALL_SETUP
Definition aoc.h:150
@ AST_AOC_CHARGED_ITEM_CALL_ATTEMPT
Definition aoc.h:149
@ AST_AOC_CHARGE_CURRENCY
Definition aoc.h:72
@ AST_AOC_CHARGE_FREE
Definition aoc.h:71
@ AST_AOC_CHARGE_UNIT
Definition aoc.h:73
enum ast_aoc_type ast_aoc_get_msg_type(struct ast_aoc_decoded *decoded)
get the message type, AOC-D, AOC-E, or AOC Request
Definition aoc.c:901
ast_aoc_currency_multiplier
Defines the currency multiplier for an aoc message.
Definition aoc.h:34
const struct ast_aoc_unit_entry * ast_aoc_get_unit_info(struct ast_aoc_decoded *decoded, unsigned int entry_number)
get a specific unit entry.
Definition aoc.c:1019
@ AST_AOC_S
Definition aoc.h:64
@ AST_AOC_D
Definition aoc.h:65
@ AST_AOC_E
Definition aoc.h:66
unsigned int ast_aoc_s_get_count(struct ast_aoc_decoded *decoded)
get the number rates associated with an AOC-S message
Definition aoc.c:765
enum ast_aoc_currency_multiplier ast_aoc_get_currency_multiplier(struct ast_aoc_decoded *decoded)
get the currency multiplier for AOC-D and AOC-E messages
Definition aoc.c:954
const struct ast_aoc_s_entry * ast_aoc_s_get_rate_info(struct ast_aoc_decoded *decoded, unsigned int entry_number)
get a specific AOC-S rate entry.
Definition aoc.c:770
enum ast_aoc_charge_type ast_aoc_get_charge_type(struct ast_aoc_decoded *decoded)
get the charging type for an AOC-D or AOC-E message
Definition aoc.c:906
unsigned int ast_aoc_get_currency_amount(struct ast_aoc_decoded *decoded)
get the currency amount for AOC-D and AOC-E messages
Definition aoc.c:949
@ AST_AOC_SUBTOTAL
Definition aoc.h:84
@ AST_AOC_RATE_TYPE_DURATION
Definition aoc.h:159
@ AST_AOC_RATE_TYPE_FLAT
Definition aoc.h:160
@ AST_AOC_RATE_TYPE_FREE
Definition aoc.h:157
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
@ AST_STATE_UP
int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint, const char *uri, struct ast_sip_contact *contact, pjsip_tx_data **tdata)
General purpose method for creating a SIP request.
Definition res_pjsip.c:1435
static const char * aoc_time_scale_str(enum ast_aoc_time_scale value)
static void aoc_xml_set_node_content(pj_pool_t *pool, pj_xml_node *node, const char *content)
static void aoc_release_pool(void *data)
static pj_xml_attr * aoc_xml_create_attr(pj_pool_t *pool, pj_xml_node *node, const char *name, const char *value)
static pj_xml_node * aoc_xml_create_node(pj_pool_t *pool, pj_xml_node *parent, const char *name)
static char * aoc_format_amount(pj_pool_t *pool, unsigned int amount, enum ast_aoc_currency_multiplier multiplier)
void ast_sip_session_send_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP request.
int ast_sip_session_add_datastore(struct ast_sip_session *session, struct ast_datastore *datastore)
Add a datastore to a SIP session.
struct ast_datastore * ast_sip_session_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
Alternative for ast_datastore_alloc()
@ AST_SIP_SESSION_OUTGOING_CALL
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
uint32_t amount
Definition aoc.h:104
char currency_name[AOC_CURRENCY_NAME_SIZE]
Definition aoc.h:114
uint16_t multiplier
Definition aoc.h:109
uint8_t charging_type
Charging interval type.
Definition aoc.h:122
uint16_t time_scale
Definition aoc.h:110
uint32_t time
Definition aoc.h:105
uint32_t amount
Definition aoc.h:139
char currency_name[AOC_CURRENCY_NAME_SIZE]
Definition aoc.h:142
uint16_t multiplier
Definition aoc.h:140
Definition aoc.h:165
struct ast_aoc_flat_rate flat
Definition aoc.h:172
uint16_t charged_item
Definition aoc.h:166
union ast_aoc_s_entry::@193 rate
Charge rate being applied.
struct ast_aoc_duration_rate duration
Definition aoc.h:171
uint16_t rate_type
Definition aoc.h:167
Definition aoc.h:178
unsigned int amount
Definition aoc.h:180

References ast_aoc_duration_rate::amount, ast_aoc_flat_rate::amount, ast_aoc_unit_entry::amount, ao2_cleanup, aoc_d_datastore, aoc_e_datastore, aoc_format_amount(), aoc_release_pool(), aoc_s_datastore, aoc_time_scale_str(), aoc_xml_create_attr(), aoc_xml_create_node(), aoc_xml_set_node_content(), AST_AOC_CHARGE_CURRENCY, AST_AOC_CHARGE_FREE, AST_AOC_CHARGE_UNIT, AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION, AST_AOC_CHARGED_ITEM_CALL_ATTEMPT, AST_AOC_CHARGED_ITEM_CALL_SETUP, AST_AOC_D, AST_AOC_E, ast_aoc_get_charge_type(), ast_aoc_get_currency_amount(), ast_aoc_get_currency_multiplier(), ast_aoc_get_currency_name(), ast_aoc_get_msg_type(), ast_aoc_get_total_type(), ast_aoc_get_unit_info(), AST_AOC_MULT_ONE, AST_AOC_RATE_TYPE_DURATION, AST_AOC_RATE_TYPE_FLAT, AST_AOC_RATE_TYPE_FREE, AST_AOC_S, ast_aoc_s_get_count(), ast_aoc_s_get_rate_info(), AST_AOC_SUBTOTAL, ast_free, ast_log, ast_sip_add_body(), ast_sip_create_request(), ast_sip_get_pjsip_endpoint(), ast_sip_session_add_datastore(), ast_sip_session_alloc_datastore(), ast_sip_session_get_datastore(), AST_SIP_SESSION_OUTGOING_CALL, ast_sip_session_send_request(), AST_STATE_UP, ast_strdup, ast_strlen_zero(), ast_aoc_s_entry::charged_item, ast_aoc_duration_rate::charging_type, ast_aoc_duration_rate::currency_name, ast_aoc_flat_rate::currency_name, ast_aoc_s_entry::duration, ast_aoc_s_entry::flat, LOG_ERROR, ast_aoc_duration_rate::multiplier, ast_aoc_flat_rate::multiplier, NULL, RAII_VAR, ast_aoc_s_entry::rate, ast_aoc_s_entry::rate_type, ast_aoc_duration_rate::time, ast_aoc_duration_rate::time_scale, ast_datastore_info::type, and ast_sip_body::type.

Referenced by aoc_framehook().

◆ aoc_time_scale_str()

static const char * aoc_time_scale_str ( enum ast_aoc_time_scale  value)
static

Definition at line 112 of file res_pjsip_aoc.c.

113{
114 const char *str;
115
116 switch (value) {
117 default:
119 str = "one-hundredth-second";
120 break;
122 str = "one-tenth-second";
123 break;
125 str = "one-second";
126 break;
128 str = "ten-seconds";
129 break;
131 str = "one-minute";
132 break;
134 str = "one-hour";
135 break;
137 str = "twenty-four-hours";
138 break;
139 }
140 return str;
141}
@ AST_AOC_TIME_SCALE_TEN_SECOND
Definition aoc.h:91
@ AST_AOC_TIME_SCALE_DAY
Definition aoc.h:94
@ AST_AOC_TIME_SCALE_TENTH_SECOND
Definition aoc.h:89
@ AST_AOC_TIME_SCALE_MINUTE
Definition aoc.h:92
@ AST_AOC_TIME_SCALE_SECOND
Definition aoc.h:90
@ AST_AOC_TIME_SCALE_HOUR
Definition aoc.h:93
@ AST_AOC_TIME_SCALE_HUNDREDTH_SECOND
Definition aoc.h:88
const char * str
Definition app_jack.c:150
int value
Definition syslog.c:37

References AST_AOC_TIME_SCALE_DAY, AST_AOC_TIME_SCALE_HOUR, AST_AOC_TIME_SCALE_HUNDREDTH_SECOND, AST_AOC_TIME_SCALE_MINUTE, AST_AOC_TIME_SCALE_SECOND, AST_AOC_TIME_SCALE_TEN_SECOND, AST_AOC_TIME_SCALE_TENTH_SECOND, str, and value.

Referenced by aoc_send_as_xml().

◆ aoc_xml_create_attr()

static pj_xml_attr * aoc_xml_create_attr ( pj_pool_t *  pool,
pj_xml_node *  node,
const char *  name,
const char *  value 
)
static

Definition at line 36 of file res_pjsip_aoc.c.

38{
39 pj_xml_attr *attr;
40
41 attr = PJ_POOL_ALLOC_T(pool, pj_xml_attr);
42
43 pj_strdup2(pool, &attr->name, name);
44 pj_strdup2(pool, &attr->value, value);
45
46 pj_xml_add_attr(node, attr);
47 return attr;
48}
static const char name[]
Definition format_mp3.c:68

References name, and value.

Referenced by aoc_send_as_xml().

◆ aoc_xml_create_node()

static pj_xml_node * aoc_xml_create_node ( pj_pool_t *  pool,
pj_xml_node *  parent,
const char *  name 
)
static

Definition at line 50 of file res_pjsip_aoc.c.

52{
53 pj_xml_node *node;
54
55 node = PJ_POOL_ZALLOC_T(pool, pj_xml_node);
56
57 pj_list_init(&node->attr_head);
58 pj_list_init(&node->node_head);
59
60 pj_strdup2(pool, &node->name, name);
61
62 if (parent) {
63 pj_xml_add_node(parent, node);
64 }
65
66 return node;
67}

References name.

Referenced by aoc_send_as_xml().

◆ aoc_xml_set_node_content()

static void aoc_xml_set_node_content ( pj_pool_t *  pool,
pj_xml_node *  node,
const char *  content 
)
static

Definition at line 69 of file res_pjsip_aoc.c.

71{
72 pj_strdup2(pool, &node->content, content);
73}

Referenced by aoc_send_as_xml().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 698 of file res_pjsip_aoc.c.

◆ load_module()

static int load_module ( void  )
static

Definition at line 678 of file res_pjsip_aoc.c.

679{
683}
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
static struct ast_sip_session_supplement aoc_bye_supplement
static struct ast_sip_session_supplement aoc_invite_supplement
#define ast_sip_session_register_supplement(supplement)

References aoc_bye_supplement, aoc_invite_supplement, AST_MODULE_LOAD_SUCCESS, and ast_sip_session_register_supplement.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 685 of file res_pjsip_aoc.c.

686{
689 return 0;
690}
void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
Unregister a an supplement to SIP session processing.

References aoc_bye_supplement, aoc_invite_supplement, and ast_sip_session_unregister_supplement().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP AOC Support" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, .requires = "res_pjsip", }
static

Definition at line 698 of file res_pjsip_aoc.c.

◆ aoc_bye_supplement

struct ast_sip_session_supplement aoc_bye_supplement
static

Definition at line 663 of file res_pjsip_aoc.c.

663 {
664 .method = "BYE",
666 .outgoing_request = aoc_bye_outgoing_request,
667 .outgoing_response = aoc_bye_outgoing_response,
668};
@ AST_SIP_SUPPLEMENT_PRIORITY_LAST
Definition res_pjsip.h:3341
static void aoc_bye_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
static void aoc_bye_outgoing_response(struct ast_sip_session *session, struct pjsip_tx_data *tdata)

Referenced by load_module(), and unload_module().

◆ aoc_d_datastore

const struct ast_datastore_info aoc_d_datastore
static
Initial value:
= {
.type = "AOC-D",
}
static void aoc_datastore_destroy(void *obj)

Definition at line 154 of file res_pjsip_aoc.c.

154 {
155 .type = "AOC-D",
156 .destroy = aoc_datastore_destroy,
157};

Referenced by aoc_bye_outgoing_request(), aoc_bye_outgoing_response(), and aoc_send_as_xml().

◆ aoc_e_datastore

const struct ast_datastore_info aoc_e_datastore
static
Initial value:
= {
.type = "AOC-E",
}

Definition at line 159 of file res_pjsip_aoc.c.

159 {
160 .type = "AOC-E",
161 .destroy = aoc_datastore_destroy,
162};

Referenced by aoc_bye_outgoing_request(), aoc_bye_outgoing_response(), and aoc_send_as_xml().

◆ aoc_invite_supplement

struct ast_sip_session_supplement aoc_invite_supplement
static

Definition at line 670 of file res_pjsip_aoc.c.

670 {
671 .method = "INVITE",
673 .incoming_request = aoc_incoming_invite_request,
674 .outgoing_request = aoc_outgoing_invite_request,
675 .outgoing_response = aoc_invite_outgoing_response,
676};
static void aoc_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
static void aoc_invite_outgoing_response(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
static int aoc_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)

Referenced by load_module(), and unload_module().

◆ aoc_s_datastore

const struct ast_datastore_info aoc_s_datastore
static
Initial value:
= {
.type = "AOC-S",
}

Definition at line 149 of file res_pjsip_aoc.c.

149 {
150 .type = "AOC-S",
151 .destroy = aoc_datastore_destroy,
152};

Referenced by aoc_invite_outgoing_response(), and aoc_send_as_xml().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 698 of file res_pjsip_aoc.c.