Asterisk - The Open Source Telephony Project GIT-master-abe0018
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 = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .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:2922
#define ast_channel_unlock(chan)
Definition: channel.h:2923
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:2325
const char * type
Definition: res_pjsip.h:2327
const char * body_text
Definition: res_pjsip.h:2331
#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:941

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[]
Definition: chan_ooh323.c:109
@ 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:307
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:449
#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
Definition: channelstate.h:35
@ 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
@ AST_CONTROL_AOC
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
union ast_frame::@226 data
enum ast_frame_type frametype
A structure which contains a channel implementation and session.
struct ast_sip_session * session
Pointer to session.
struct ast_taskprocessor * serializer
Definition: astman.c:222

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
350 if (entry->charged_item == AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION) {
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
373 if (entry->rate_type == AST_AOC_RATE_TYPE_DURATION ||
374 entry->rate_type == AST_AOC_RATE_TYPE_FLAT) {
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 ?
382 entry->rate.duration.currency_name :
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
400 if (entry->rate_type == AST_AOC_RATE_TYPE_DURATION) {
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,
414 aoc_time_scale_str(entry->rate.duration.time_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:914
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:972
@ 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:892
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:1010
@ 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:756
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:945
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:761
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:897
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:940
@ 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
Definition: channelstate.h:42
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)
Definition: res_pjsip_aoc.c:69
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)
Definition: res_pjsip_aoc.c:36
static pj_xml_node * aoc_xml_create_node(pj_pool_t *pool, pj_xml_node *parent, const char *name)
Definition: res_pjsip_aoc.c:50
static char * aoc_format_amount(pj_pool_t *pool, unsigned int amount, enum ast_aoc_currency_multiplier multiplier)
Definition: res_pjsip_aoc.c:75
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
Definition: aoc.h:165
uint16_t charged_item
Definition: aoc.h:166
Definition: aoc.h:178
unsigned int amount
Definition: aoc.h:180
Definition: search.h:40

References 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, LOG_ERROR, NULL, RAII_VAR, 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:147
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
Definition: test_heap.c:38

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.
Definition: pjsip_session.c:63

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 = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .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.

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.

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.

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.

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.

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.