Asterisk - The Open Source Telephony Project GIT-master-d5a0626
res_pjsip_aoc.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2022, Michael Kuron
5 *
6 * Michael Kuron <m.kuron@gmx.de>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*** MODULEINFO
20 <depend>pjproject</depend>
21 <depend>res_pjsip</depend>
22 <support_level>extended</support_level>
23 ***/
24
25#include "asterisk.h"
26
27#include <pjsip.h>
28#include <pjlib.h>
29
30#include "asterisk/aoc.h"
31#include "asterisk/module.h"
32#include "asterisk/pbx.h"
33#include "asterisk/res_pjsip.h"
35
36static pj_xml_attr *aoc_xml_create_attr(pj_pool_t *pool, pj_xml_node *node,
37 const char *name, const char *value)
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}
49
50static pj_xml_node *aoc_xml_create_node(pj_pool_t *pool, pj_xml_node *parent,
51 const char *name)
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}
68
69static void aoc_xml_set_node_content(pj_pool_t *pool, pj_xml_node *node,
70 const char *content)
71{
72 pj_strdup2(pool, &node->content, content);
73}
74
75static char * aoc_format_amount(pj_pool_t *pool, unsigned int amount,
76 enum ast_aoc_currency_multiplier multiplier)
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}
111
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}
142
143static void aoc_datastore_destroy(void *obj)
144{
145 char *xml = obj;
146 ast_free(xml);
147}
148
149static const struct ast_datastore_info aoc_s_datastore = {
150 .type = "AOC-S",
151 .destroy = aoc_datastore_destroy,
152};
153
154static const struct ast_datastore_info aoc_d_datastore = {
155 .type = "AOC-D",
156 .destroy = aoc_datastore_destroy,
157};
158
159static const struct ast_datastore_info aoc_e_datastore = {
160 .type = "AOC-E",
161 .destroy = aoc_datastore_destroy,
162};
163
164struct aoc_data {
168};
169
170static void aoc_release_pool(void * data)
171{
172 pj_pool_t *pool = data;
173 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
174}
175
176static int aoc_send_as_xml(void * data)
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}
473
474static void aoc_data_destroy(void * data)
475{
476 struct aoc_data *adata = data;
477
479 ao2_cleanup(adata->session);
480}
481
482static struct ast_frame *aoc_framehook(struct ast_channel *ast, struct ast_frame *f,
483 enum ast_framehook_event event, void *data)
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}
516
517static int aoc_consume(void *data, enum ast_frame_type type)
518{
519 return (type == AST_FRAME_CONTROL) ? 1 : 0;
520}
521
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}
545
547 struct pjsip_rx_data *rdata)
548{
550 return 0;
551}
552
554 struct pjsip_tx_data *tdata)
555{
557}
558
560 struct pjsip_tx_data *tdata)
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}
584
586 struct pjsip_tx_data *tdata)
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}
610
612 struct pjsip_tx_data *tdata)
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}
662
664 .method = "BYE",
666 .outgoing_request = aoc_bye_outgoing_request,
667 .outgoing_response = aoc_bye_outgoing_response,
668};
669
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};
677
678static int load_module(void)
679{
683}
684
685static int unload_module(void)
686{
689 return 0;
690}
691
693 .support_level = AST_MODULE_SUPPORT_EXTENDED,
694 .load = load_module,
695 .unload = unload_module,
696 .load_pri = AST_MODPRI_CHANNEL_DEPEND,
697 .requires = "res_pjsip",
Generic Advice of Charge encode and decode routines.
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
ast_aoc_time_scale
Definition: aoc.h:87
@ 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
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
@ 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
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
void * ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
free an ast_aoc_decoded object
Definition: aoc.c:307
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
const char * str
Definition: app_jack.c:147
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_mansession session
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#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
static const char type[]
Definition: chan_ooh323.c:109
const char * ast_channel_name(const struct ast_channel *chan)
void * ast_channel_tech_pvt(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition: channel.h:2968
#define ast_channel_unlock(chan)
Definition: channel.h:2969
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
static const char name[]
Definition: format_mp3.c:68
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
ast_framehook_event
These are the types of events that the framehook's event callback can receive.
Definition: framehook.h:151
@ AST_FRAMEHOOK_EVENT_WRITE
Definition: framehook.h:153
#define AST_FRAMEHOOK_INTERFACE_VERSION
Definition: framehook.h:227
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_frame_type
Frame types.
@ AST_FRAME_CONTROL
@ AST_CONTROL_AOC
struct ast_frame ast_null_frame
Definition: main/frame.c:79
#define LOG_ERROR
#define LOG_WARNING
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODPRI_CHANNEL_DEPEND
Definition: module.h:340
@ AST_MODULE_SUPPORT_EXTENDED
Definition: module.h:122
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
Core PBX routines and definitions.
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:520
@ AST_SIP_SUPPLEMENT_PRIORITY_LAST
Definition: res_pjsip.h:3188
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
pjsip_media_type pjsip_media_type_multipart_mixed
Definition: res_pjsip.c:3918
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 int aoc_consume(void *data, enum ast_frame_type type)
static void aoc_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
static struct ast_frame * aoc_framehook(struct ast_channel *ast, struct ast_frame *f, enum ast_framehook_event event, void *data)
static const struct ast_datastore_info aoc_s_datastore
static const struct ast_datastore_info aoc_e_datastore
static void aoc_attach_framehook(struct ast_sip_session *session)
static void aoc_invite_outgoing_response(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
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 void aoc_data_destroy(void *data)
static struct ast_sip_session_supplement aoc_bye_supplement
static const struct ast_datastore_info aoc_d_datastore
static void aoc_bye_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
static int load_module(void)
static void aoc_bye_outgoing_response(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
static int unload_module(void)
static struct ast_sip_session_supplement aoc_invite_supplement
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 void aoc_datastore_destroy(void *obj)
static int aoc_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
static char * aoc_format_amount(pj_pool_t *pool, unsigned int amount, enum ast_aoc_currency_multiplier multiplier)
Definition: res_pjsip_aoc.c:75
static int aoc_send_as_xml(void *data)
void ast_sip_session_send_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
Send a SIP request.
struct ast_datastore * ast_sip_session_get_datastore(struct ast_sip_session *session, const char *name)
Retrieve a session datastore.
int ast_sip_session_add_datastore(struct ast_sip_session *session, struct ast_datastore *datastore)
Add a datastore to a SIP session.
#define ast_sip_session_register_supplement(supplement)
struct ast_datastore * ast_sip_session_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
Alternative for ast_datastore_alloc()
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
@ AST_SIP_SESSION_OUTGOING_CALL
#define NULL
Definition: resample.c:96
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
struct ast_sip_session * session
enum ast_channel_state channel_state
struct ast_aoc_decoded * decoded
Definition: aoc.h:165
uint16_t charged_item
Definition: aoc.h:166
Definition: aoc.h:178
unsigned int amount
Definition: aoc.h:180
Main Channel structure associated with a channel.
Structure for a data store type.
Definition: datastore.h:31
const char * type
Definition: datastore.h:32
Structure for a data store object.
Definition: datastore.h:64
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@226 data
enum ast_frame_type frametype
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
const char * subtype
Definition: res_pjsip.h:2329
A structure which contains a channel implementation and session.
struct ast_sip_session * session
Pointer to session.
A supplement to SIP message processing.
A structure describing a SIP session.
struct ast_taskprocessor * serializer
Definition: search.h:40
Definition: astman.c:222
Definition: test_heap.c:38
int value
Definition: syslog.c:37
#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