Asterisk - The Open Source Telephony Project GIT-master-67613d1
cdr.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2006, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
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/*! \file
20 *
21 * \brief Call Detail Record API
22 *
23 * \author Mark Spencer <markster@digium.com>
24 *
25 * \note Includes code and algorithms from the Zapata library.
26 *
27 * \note We do a lot of checking here in the CDR code to try to be sure we don't ever let a CDR slip
28 * through our fingers somehow. If someone allocates a CDR, it must be completely handled normally
29 * or a WARNING shall be logged, so that we can best keep track of any escape condition where the CDR
30 * isn't properly generated and posted.
31 */
32
33/*! \li \ref cdr.c uses the configuration file \ref cdr.conf
34 * \addtogroup configuration_file Configuration Files
35 */
36
37/*!
38 * \page cdr.conf cdr.conf
39 * \verbinclude cdr.conf.sample
40 */
41
42/*** MODULEINFO
43 <support_level>core</support_level>
44 ***/
45
46#include "asterisk.h"
47
48#include <signal.h>
49#include <inttypes.h>
50
51#include "asterisk/lock.h"
52#include "asterisk/channel.h"
53#include "asterisk/cdr.h"
54#include "asterisk/callerid.h"
55#include "asterisk/manager.h"
56#include "asterisk/module.h"
57#include "asterisk/causes.h"
59#include "asterisk/utils.h"
60#include "asterisk/sched.h"
61#include "asterisk/config.h"
62#include "asterisk/cli.h"
65#include "asterisk/json.h"
66#include "asterisk/parking.h"
67#include "asterisk/stasis.h"
71#include "asterisk/astobj2.h"
73
74/*** DOCUMENTATION
75 <configInfo name="cdr" language="en_US">
76 <synopsis>Call Detail Record configuration</synopsis>
77 <description>
78 <para>CDR is Call Detail Record, which provides logging services via a variety of
79 pluggable backend modules. Detailed call information can be recorded to
80 databases, files, etc. Useful for billing, fraud prevention, compliance with
81 Sarbanes-Oxley aka The Enron Act, QOS evaluations, and more.</para>
82 </description>
83 <configFile name="cdr.conf">
84 <configObject name="general">
85 <synopsis>Global settings applied to the CDR engine.</synopsis>
86 <configOption name="debug">
87 <synopsis>Enable/disable verbose CDR debugging.</synopsis>
88 <description><para>When set to <literal>True</literal>, verbose updates
89 of changes in CDR information will be logged. Note that this is only
90 of use when debugging CDR behavior.</para>
91 </description>
92 </configOption>
93 <configOption name="enable" default="yes">
94 <synopsis>Enable/disable CDR logging.</synopsis>
95 <description><para>Define whether or not to use CDR logging. Setting this to "no" will override
96 any loading of backend CDR modules.</para>
97 </description>
98 </configOption>
99 <configOption name="channeldefaultenabled" default="yes">
100 <synopsis>Whether CDR is enabled on a channel by default</synopsis>
101 <description><para>Define whether or not CDR should be enabled on a channel by default.
102 Setting this to "yes" will enable CDR on every channel unless it is explicitly disabled.
103 Setting this to "no" will disable CDR on every channel unless it is explicitly enabled.
104 </para>
105 <para>Note that CDR must still be globally enabled (<literal>enable = yes</literal>) for this
106 option to have any effect. This only applies to whether CDR is enabled or disabled on
107 newly created channels, which can be changed in the dialplan during a call.</para>
108 <para>If this is set to "yes", you should use <literal>Set(CDR_PROP(disable)=1)</literal>
109 to disable CDR for a call.</para>
110 <para>If this is set to "no", you should use <literal>Set(CDR_PROP(disable)=0)</literal>
111 to undisable (enable) CDR for a call.</para>
112 </description>
113 </configOption>
114 <configOption name="ignorestatechanges" default="no">
115 <synopsis>Whether CDR is updated or forked by bridging changes.</synopsis>
116 <description><para>Define whether or not CDR should be updated by bridging changes.
117 This includes entering and leaving bridges and call parking.</para>
118 <para>If this is set to "no", bridging changes will be ignored for all CDRs.
119 This should only be done if these events should not affect CDRs and are undesired,
120 such as to use a single CDR for the lifetime of the channel.</para>
121 <para>This setting cannot be changed on a reload.</para>
122 </description>
123 </configOption>
124 <configOption name="ignoredialchanges" default="no">
125 <synopsis>Whether CDR is updated or forked by dial updates.</synopsis>
126 <description><para>Define whether or not CDR should be updated by dial updates.</para>
127 <para>If this is set to "no", a single CDR will be used for the channel, even if
128 multiple endpoints or destinations are dialed sequentially. Note that you will also
129 lose detailed nonanswer dial dispositions if this option is enabled, which may not be acceptable,
130 e.g. instead of detailed no-answer dispositions like BUSY and CONGESTION, the disposition
131 will always be NO ANSWER if the channel was unanswered (it will still be ANSWERED
132 if the channel was answered).</para>
133 <para>This option should be enabled if a single CDR is desired for the lifetime of
134 the channel.</para>
135 </description>
136 </configOption>
137 <configOption name="unanswered">
138 <synopsis>Log calls that are never answered and don't set an outgoing party.</synopsis>
139 <description><para>
140 Define whether or not to log unanswered calls that don't involve an outgoing party. Setting
141 this to "yes" will make calls to extensions that don't answer and don't set a side B channel
142 (such as by using the Dial application) receive CDR log entries. If this option is set to
143 "no", then those log entries will not be created. Unanswered calls which get offered to an
144 outgoing line will always receive log entries regardless of this option, and that is the
145 intended behavior.
146 </para>
147 </description>
148 </configOption>
149 <configOption name="congestion">
150 <synopsis>Log congested calls.</synopsis>
151 <description><para>Define whether or not to log congested calls. Setting this to "yes" will
152 report each call that fails to complete due to congestion conditions.</para>
153 </description>
154 </configOption>
155 <configOption name="endbeforehexten">
156 <synopsis>Don't produce CDRs while executing hangup logic</synopsis>
157 <description>
158 <para>As each CDR for a channel is finished, its end time is updated
159 and the CDR is finalized. When a channel is hung up and hangup
160 logic is present (in the form of a hangup handler or the
161 <literal>h</literal> extension), a new CDR is generated for the
162 channel. Any statistics are gathered from this new CDR. By enabling
163 this option, no new CDR is created for the dialplan logic that is
164 executed in <literal>h</literal> extensions or attached hangup handler
165 subroutines. The default value is <literal>yes</literal>, indicating
166 that a CDR will be generated during hangup logic.</para>
167 </description>
168 </configOption>
169 <configOption name="initiatedseconds">
170 <synopsis>Count microseconds for billsec purposes</synopsis>
171 <description><para>Normally, the <literal>billsec</literal> field logged to the CDR backends
172 is simply the end time (hangup time) minus the answer time in seconds. Internally,
173 asterisk stores the time in terms of microseconds and seconds. By setting
174 initiatedseconds to <literal>yes</literal>, you can force asterisk to report any seconds
175 that were initiated (a sort of round up method). Technically, this is
176 when the microsecond part of the end time is greater than the microsecond
177 part of the answer time, then the billsec time is incremented one second.</para>
178 </description>
179 </configOption>
180 <configOption name="batch">
181 <synopsis>Submit CDRs to the backends for processing in batches</synopsis>
182 <description><para>Define the CDR batch mode, where instead of posting the CDR at the end of
183 every call, the data will be stored in a buffer to help alleviate load on the
184 asterisk server.</para>
185 <warning><para>Use of batch mode may result in data loss after unsafe asterisk termination,
186 i.e., software crash, power failure, kill -9, etc.</para>
187 </warning>
188 </description>
189 </configOption>
190 <configOption name="size">
191 <synopsis>The maximum number of CDRs to accumulate before triggering a batch</synopsis>
192 <description><para>Define the maximum number of CDRs to accumulate in the buffer before posting
193 them to the backend engines. batch must be set to <literal>yes</literal>.</para>
194 </description>
195 </configOption>
196 <configOption name="time">
197 <synopsis>The maximum time to accumulate CDRs before triggering a batch</synopsis>
198 <description><para>Define the maximum time to accumulate CDRs before posting them in a batch to the
199 backend engines. If this time limit is reached, then it will post the records, regardless of the value
200 defined for size. batch must be set to <literal>yes</literal>.</para>
201 <note><para>Time is expressed in seconds.</para></note>
202 </description>
203 </configOption>
204 <configOption name="scheduleronly">
205 <synopsis>Post batched CDRs on their own thread instead of the scheduler</synopsis>
206 <description><para>The CDR engine uses the internal asterisk scheduler to determine when to post
207 records. Posting can either occur inside the scheduler thread, or a new
208 thread can be spawned for the submission of every batch. For small batches,
209 it might be acceptable to just use the scheduler thread, so set this to <literal>yes</literal>.
210 For large batches, say anything over size=10, a new thread is recommended, so
211 set this to <literal>no</literal>.</para>
212 </description>
213 </configOption>
214 <configOption name="safeshutdown">
215 <synopsis>Block shutdown of Asterisk until CDRs are submitted</synopsis>
216 <description><para>When shutting down asterisk, you can block until the CDRs are submitted. If
217 you don't, then data will likely be lost. You can always check the size of
218 the CDR batch buffer with the CLI <astcli>cdr status</astcli> command. To enable blocking on
219 submission of CDR data during asterisk shutdown, set this to <literal>yes</literal>.</para>
220 </description>
221 </configOption>
222 </configObject>
223 </configFile>
224 </configInfo>
225 ***/
226
227#define DEFAULT_ENABLED "1"
228#define DEFAULT_BATCHMODE "0"
229#define DEFAULT_UNANSWERED "0"
230#define DEFAULT_CONGESTION "0"
231#define DEFAULT_END_BEFORE_H_EXTEN "1"
232#define DEFAULT_INITIATED_SECONDS "0"
233#define DEFAULT_CHANNEL_ENABLED "1"
234#define DEFAULT_IGNORE_STATE_CHANGES "0"
235#define DEFAULT_IGNORE_DIAL_CHANGES "0"
236
237#define DEFAULT_BATCH_SIZE "100"
238#define MAX_BATCH_SIZE 1000
239#define DEFAULT_BATCH_TIME "300"
240#define MAX_BATCH_TIME 86400
241#define DEFAULT_BATCH_SCHEDULER_ONLY "0"
242#define DEFAULT_BATCH_SAFE_SHUTDOWN "1"
243
244#define cdr_set_debug_mode(mod_cfg) \
245 do { \
246 cdr_debug_enabled = ast_test_flag(&(mod_cfg)->general->settings, CDR_DEBUG); \
247 } while (0)
248
251
252#define CDR_DEBUG(fmt, ...) \
253 do { \
254 if (cdr_debug_enabled) { \
255 ast_verbose((fmt), ##__VA_ARGS__); \
256 } \
257 } while (0)
258
259static void cdr_detach(struct ast_cdr *cdr);
260static void cdr_submit_batch(int shutdown);
261static int cdr_toggle_runtime_options(void);
262
263/*! \brief The configuration settings for this module */
265 struct ast_cdr_config *general; /*!< CDR global settings */
266};
267
268/*! \brief The container for the module configuration */
269static AO2_GLOBAL_OBJ_STATIC(module_configs);
270
271/*! \brief The type definition for general options */
272static struct aco_type general_option = {
273 .type = ACO_GLOBAL,
274 .name = "general",
275 .item_offset = offsetof(struct module_config, general),
276 .category = "general",
277 .category_match = ACO_WHITELIST_EXACT,
278};
279
280/*! Config sections used by existing modules. Do not add to this list. */
281static const char *ignore_categories[] = {
282 "csv",
283 "custom",
284 "manager",
285 "odbc",
286 "pgsql",
287 "radius",
288 "sqlite",
289 "tds",
290 "mysql",
291 NULL,
292};
293
294static struct aco_type ignore_option = {
295 .type = ACO_IGNORE,
296 .name = "modules",
297 .category = (const char*)ignore_categories,
299};
300
301static void *module_config_alloc(void);
302static void module_config_destructor(void *obj);
303static void module_config_post_apply(void);
304
305/*! \brief The file definition */
306static struct aco_file module_file_conf = {
307 .filename = "cdr.conf",
309};
310
311CONFIG_INFO_CORE("cdr", cfg_info, module_configs, module_config_alloc,
312 .files = ACO_FILES(&module_file_conf),
313 .post_apply_config = module_config_post_apply,
314);
315
317
319{
320 struct module_config *mod_cfg;
321
322 mod_cfg = ao2_global_obj_ref(module_configs);
323 if (!mod_cfg) {
324 return;
325 }
326 cdr_set_debug_mode(mod_cfg);
327 ao2_cleanup(mod_cfg);
328}
329
330/*! \brief Dispose of a module config object */
331static void module_config_destructor(void *obj)
332{
333 struct module_config *cfg = obj;
334
335 if (!cfg) {
336 return;
337 }
338 ao2_ref(cfg->general, -1);
339}
340
341/*! \brief Create a new module config object */
342static void *module_config_alloc(void)
343{
344 struct module_config *mod_cfg;
346
347 mod_cfg = ao2_alloc(sizeof(*mod_cfg), module_config_destructor);
348 if (!mod_cfg) {
349 return NULL;
350 }
351
352 cdr_config = ao2_alloc(sizeof(*cdr_config), NULL);
353 if (!cdr_config) {
354 ao2_ref(cdr_config, -1);
355 return NULL;
356 }
357 mod_cfg->general = cdr_config;
358
359 return mod_cfg;
360}
361
362/*! \brief Registration object for CDR backends */
364 char name[20];
365 char desc[80];
368 int suspended:1;
369};
370
371/*! \brief List of registered backends */
373
374/*! \brief List of registered modifiers */
376
377/*! \brief Queued CDR waiting to be batched */
379 struct ast_cdr *cdr;
381};
382
383/*! \brief The actual batch queue */
384static struct cdr_batch {
385 int size;
389
390/*! \brief The global sequence counter used for CDRs */
391static int global_cdr_sequence = 0;
392
393/*! \brief Scheduler items */
395static int cdr_sched = -1;
397static pthread_t cdr_thread = AST_PTHREADT_NULL;
398
399/*! \brief Lock protecting modifications to the batch queue */
401
402/*! \brief These are used to wake up the CDR thread when there's work to do */
405
406/*! \brief A container of the active master CDRs indexed by Party A channel uniqueid */
408
409/*! \brief A container of all active CDRs with a Party B indexed by Party B channel name */
411
412/*! \brief Message router for stasis messages regarding channel state */
414
415/*! \brief Our subscription for bridges */
417
418/*! \brief Our subscription for channels */
420
421/*! \brief Our subscription for parking */
423
424/*! \brief The parent topic for all topics we want to aggregate for CDRs */
425static struct stasis_topic *cdr_topic;
426
427/*! \brief A message type used to synchronize with the CDR topic */
428STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_sync_message_type);
429
430struct cdr_object;
431
432/*! \brief Return types for \p process_bridge_enter functions */
434 /*!
435 * The CDR was the only party in the bridge.
436 */
438 /*!
439 * The CDR was able to obtain a Party B from some other party already in the bridge
440 */
442 /*!
443 * The CDR was not able to obtain a Party B
444 */
446 /*!
447 * This CDR can't handle a bridge enter message and a new CDR needs to be created
448 */
450};
451
452/*!
453 * \brief A virtual table used for \ref cdr_object.
454 *
455 * Note that all functions are optional - if a subclass does not need an
456 * implementation, it is safe to leave it NULL.
457 */
459 /*! \brief Name of the subclass */
460 const char *name;
461
462 /*!
463 * \brief An initialization function. This will be called automatically
464 * when a \ref cdr_object is switched to this type in
465 * \ref cdr_object_transition_state
466 *
467 * \param cdr The \ref cdr_object that was just transitioned
468 */
469 void (* const init_function)(struct cdr_object *cdr);
470
471 /*!
472 * \brief Process a Party A update for the \ref cdr_object
473 *
474 * \param cdr The \ref cdr_object to process the update
475 * \param snapshot The snapshot for the CDR's Party A
476 * \retval 0 the CDR handled the update or ignored it
477 * \retval 1 the CDR is finalized and a new one should be made to handle it
478 */
479 int (* const process_party_a)(struct cdr_object *cdr,
480 struct ast_channel_snapshot *snapshot);
481
482 /*!
483 * \brief Process a Party B update for the \ref cdr_object
484 *
485 * \param cdr The \ref cdr_object to process the update
486 * \param snapshot The snapshot for the CDR's Party B
487 */
488 void (* const process_party_b)(struct cdr_object *cdr,
489 struct ast_channel_snapshot *snapshot);
490
491 /*!
492 * \brief Process the beginning of a dial. A dial message implies one of two
493 * things:
494 * The \ref cdr_object's Party A has been originated
495 * The \ref cdr_object's Party A is dialing its Party B
496 *
497 * \param cdr The \ref cdr_object
498 * \param caller The originator of the dial attempt
499 * \param peer The destination of the dial attempt
500 *
501 * \retval 0 if the parties in the dial were handled by this CDR
502 * \retval 1 if the parties could not be handled by this CDR
503 */
504 int (* const process_dial_begin)(struct cdr_object *cdr,
506 struct ast_channel_snapshot *peer);
507
508 /*!
509 * \brief Process the end of a dial. At the end of a dial, a CDR can be
510 * transitioned into one of two states - DialedPending
511 * (\ref dialed_pending_state_fn_table) or Finalized
512 * (\ref finalized_state_fn_table).
513 *
514 * \param cdr The \ref cdr_object
515 * \param caller The originator of the dial attempt
516 * \param peer the Destination of the dial attempt
517 * \param dial_status What happened
518 *
519 * \retval 0 if the parties in the dial were handled by this CDR
520 * \retval 1 if the parties could not be handled by this CDR
521 */
522 int (* const process_dial_end)(struct cdr_object *cdr,
525 const char *dial_status);
526
527 /*!
528 * \brief Process the entering of a bridge by this CDR. The purpose of this
529 * callback is to have the CDR prepare itself for the bridge and attempt to
530 * find a valid Party B. The act of creating new CDRs based on the entering
531 * of this channel into the bridge is handled by the higher level message
532 * handler.
533 *
534 * Note that this handler is for when a channel enters into a "normal"
535 * bridge, where people actually talk to each other. Parking is its own
536 * thing.
537 *
538 * \param cdr The \ref cdr_object
539 * \param bridge The bridge that the Party A just entered into
540 * \param channel The \ref ast_channel_snapshot for this CDR's Party A
541 *
542 * \return process_bridge_enter_results Defines whether or not this CDR was able
543 * to fully handle the bridge enter message.
544 */
546 struct cdr_object *cdr,
547 struct ast_bridge_snapshot *bridge,
548 struct ast_channel_snapshot *channel);
549
550 /*!
551 * \brief Process entering into a parking bridge.
552 *
553 * \param cdr The \ref cdr_object
554 * \param bridge The parking bridge that Party A just entered into
555 * \param channel The \ref ast_channel_snapshot for this CDR's Party A
556 *
557 * \retval 0 This CDR successfully transitioned itself into the parked state
558 * \retval 1 This CDR couldn't handle the parking transition and we need a
559 * new CDR.
560 */
561 int (* const process_parking_bridge_enter)(struct cdr_object *cdr,
562 struct ast_bridge_snapshot *bridge,
563 struct ast_channel_snapshot *channel);
564
565 /*!
566 * \brief Process the leaving of a bridge by this CDR.
567 *
568 * \param cdr The \ref cdr_object
569 * \param bridge The bridge that the Party A just left
570 * \param channel The \ref ast_channel_snapshot for this CDR's Party A
571 *
572 * \retval 0 This CDR left successfully
573 * \retval 1 Error
574 */
575 int (* const process_bridge_leave)(struct cdr_object *cdr,
576 struct ast_bridge_snapshot *bridge,
577 struct ast_channel_snapshot *channel);
578
579 /*!
580 * \brief Process an update informing us that the channel got itself parked
581 *
582 * \param cdr The \ref cdr_object
583 * \param channel The parking information for this CDR's party A
584 *
585 * \retval 0 This CDR successfully parked itself
586 * \retval 1 This CDR couldn't handle the park
587 */
588 int (* const process_parked_channel)(struct cdr_object *cdr,
589 struct ast_parked_call_payload *parking_info);
590};
591
592static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
594static int base_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
595static int base_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status);
596static int base_process_parked_channel(struct cdr_object *cdr, struct ast_parked_call_payload *parking_info);
597
598static void single_state_init_function(struct cdr_object *cdr);
599static void single_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
600static int single_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer);
602static int single_state_process_parking_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
603
604/*!
605 * \brief The virtual table for the Single state.
606 *
607 * A \ref cdr_object starts off in this state. This represents a channel that
608 * has no Party B information itself.
609 *
610 * A \ref cdr_object from this state can go into any of the following states:
611 * * \ref dial_state_fn_table
612 * * \ref bridge_state_fn_table
613 * * \ref finalized_state_fn_table
614 */
616 .name = "Single",
617 .init_function = single_state_init_function,
618 .process_party_a = base_process_party_a,
619 .process_party_b = single_state_process_party_b,
620 .process_dial_begin = single_state_process_dial_begin,
621 .process_dial_end = base_process_dial_end,
622 .process_bridge_enter = single_state_process_bridge_enter,
623 .process_parking_bridge_enter = single_state_process_parking_bridge_enter,
624 .process_bridge_leave = base_process_bridge_leave,
625 .process_parked_channel = base_process_parked_channel,
626};
627
628static void dial_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
629static int dial_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer);
630static int dial_state_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status);
632
633/*!
634 * \brief The virtual table for the Dial state.
635 *
636 * A \ref cdr_object that has begun a dial operation. This state is entered when
637 * the Party A for a CDR is determined to be dialing out to a Party B or when
638 * a CDR is for an originated channel (in which case the Party A information is
639 * the originated channel, and there is no Party B).
640 *
641 * A \ref cdr_object from this state can go in any of the following states:
642 * * \ref dialed_pending_state_fn_table
643 * * \ref bridge_state_fn_table
644 * * \ref finalized_state_fn_table
645 */
647 .name = "Dial",
648 .process_party_a = base_process_party_a,
649 .process_party_b = dial_state_process_party_b,
650 .process_dial_begin = dial_state_process_dial_begin,
651 .process_dial_end = dial_state_process_dial_end,
652 .process_bridge_enter = dial_state_process_bridge_enter,
653 .process_bridge_leave = base_process_bridge_leave,
654};
655
656static int dialed_pending_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
657static int dialed_pending_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer);
660
661/*!
662 * \brief The virtual table for the Dialed Pending state.
663 *
664 * A \ref cdr_object that has successfully finished a dial operation, but we
665 * don't know what they're going to do yet. It's theoretically possible to dial
666 * a party and then have that party not be bridged with the caller; likewise,
667 * an origination can complete and the channel go off and execute dialplan. The
668 * pending state acts as a bridge between either:
669 * * Entering a bridge
670 * * Getting a new CDR for new dialplan execution
671 * * Switching from being originated to executing dialplan
672 *
673 * A \ref cdr_object from this state can go in any of the following states:
674 * * \ref single_state_fn_table
675 * * \ref dialed_pending_state_fn_table
676 * * \ref bridge_state_fn_table
677 * * \ref finalized_state_fn_table
678 */
680 .name = "DialedPending",
681 .process_party_a = dialed_pending_state_process_party_a,
682 .process_dial_begin = dialed_pending_state_process_dial_begin,
683 .process_bridge_enter = dialed_pending_state_process_bridge_enter,
684 .process_parking_bridge_enter = dialed_pending_state_process_parking_bridge_enter,
685 .process_bridge_leave = base_process_bridge_leave,
686 .process_parked_channel = base_process_parked_channel,
687};
688
689static void bridge_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
690static int bridge_state_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
691
692/*!
693 * \brief The virtual table for the Bridged state
694 *
695 * A \ref cdr_object enters this state when it receives notification that the
696 * channel has entered a bridge.
697 *
698 * A \ref cdr_object from this state can go to:
699 * * \ref finalized_state_fn_table
700 */
702 .name = "Bridged",
703 .process_party_a = base_process_party_a,
704 .process_party_b = bridge_state_process_party_b,
705 .process_bridge_leave = bridge_state_process_bridge_leave,
706 .process_parked_channel = base_process_parked_channel,
707};
708
709static int parked_state_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
710
711/*!
712 * \brief The virtual table for the Parked state
713 *
714 * Parking is weird. Unlike typical bridges, it has to be treated somewhat
715 * uniquely - a channel in a parking bridge (which is a subclass of a holding
716 * bridge) has to be handled as if the channel went into an application.
717 * However, when the channel comes out, we need a new CDR - unlike the Single
718 * state.
719 */
721 .name = "Parked",
722 .process_party_a = base_process_party_a,
723 .process_bridge_leave = parked_state_process_bridge_leave,
724 .process_parked_channel = base_process_parked_channel,
725};
726
727static void finalized_state_init_function(struct cdr_object *cdr);
728static int finalized_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
729
730/*!
731 * \brief The virtual table for the finalized state.
732 *
733 * Once in the finalized state, the CDR is done. No modifications can be made
734 * to the CDR.
735 */
737 .name = "Finalized",
738 .init_function = finalized_state_init_function,
739 .process_party_a = finalized_state_process_party_a,
740 .process_bridge_enter = base_process_bridge_enter,
741};
742
743/*! \brief A wrapper object around a snapshot.
744 * Fields that are mutable by the CDR engine are replicated here.
745 */
747 struct ast_channel_snapshot *snapshot; /*!< The channel snapshot */
748 char userfield[AST_MAX_USER_FIELD]; /*!< Userfield for the channel */
749 unsigned int flags; /*!< Specific flags for this party */
750 struct varshead variables; /*!< CDR variables for the channel */
751};
752
753/*! \brief An in-memory representation of an active CDR */
755 struct cdr_object_snapshot party_a; /*!< The Party A information */
756 struct cdr_object_snapshot party_b; /*!< The Party B information */
757 struct cdr_object_fn_table *fn_table; /*!< The current virtual table */
758
759 enum ast_cdr_disposition disposition; /*!< The disposition of the CDR */
760 struct timeval start; /*!< When this CDR was created */
761 struct timeval answer; /*!< Either when the channel was answered, or when the path between channels was established */
762 struct timeval end; /*!< When this CDR was finalized */
763 struct timeval lastevent; /*!< The time at which the last event was created regarding this CDR */
764 unsigned int sequence; /*!< A monotonically increasing number for each CDR */
765 struct ast_flags flags; /*!< Flags on the CDR */
767 AST_STRING_FIELD(linkedid); /*!< Linked ID. Cached here as it may change out from party A, which must be immutable */
768 AST_STRING_FIELD(uniqueid); /*!< Unique id of party A. Cached here as it is the master CDR container key */
769 AST_STRING_FIELD(name); /*!< Channel name of party A. Cached here as the party A address may change */
770 AST_STRING_FIELD(bridge); /*!< The bridge the party A happens to be in. */
771 AST_STRING_FIELD(appl); /*!< The last accepted application party A was in */
772 AST_STRING_FIELD(data); /*!< The data for the last accepted application party A was in */
773 AST_STRING_FIELD(context); /*!< The accepted context for Party A */
774 AST_STRING_FIELD(exten); /*!< The accepted extension for Party A */
775 AST_STRING_FIELD(party_b_name); /*!< Party B channel name. Cached here as it is the all CDRs container key */
776 );
777 struct cdr_object *next; /*!< The next CDR object in the chain */
778 struct cdr_object *last; /*!< The last CDR object in the chain */
779 int is_root; /*!< True if this is the first CDR in the chain */
780};
781
782/*!
783 * \brief Copy variables from one list to another
784 * \param to_list destination
785 * \param from_list source
786 * \return The number of copied variables
787 */
788static int copy_variables(struct varshead *to_list, struct varshead *from_list)
789{
790 struct ast_var_t *variables;
791 struct ast_var_t *newvariable;
792 const char *var;
793 const char *val;
794 int x = 0;
795
796 AST_LIST_TRAVERSE(from_list, variables, entries) {
797 var = ast_var_name(variables);
798 if (ast_strlen_zero(var)) {
799 continue;
800 }
801 val = ast_var_value(variables);
802 if (ast_strlen_zero(val)) {
803 continue;
804 }
805 newvariable = ast_var_assign(var, val);
806 if (newvariable) {
807 AST_LIST_INSERT_HEAD(to_list, newvariable, entries);
808 ++x;
809 }
810 }
811
812 return x;
813}
814
815/*!
816 * \brief Delete all variables from a variable list
817 * \param headp The head pointer to the variable list to delete
818 */
819static void free_variables(struct varshead *headp)
820{
821 struct ast_var_t *vardata;
822
823 while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries))) {
824 ast_var_delete(vardata);
825 }
826}
827
828/*!
829 * \brief Copy a snapshot and its details
830 * \param dst The destination
831 * \param src The source
832 */
834{
835 ao2_t_replace(dst->snapshot, src->snapshot, "CDR snapshot copy");
836 strcpy(dst->userfield, src->userfield);
837 dst->flags = src->flags;
838 copy_variables(&dst->variables, &src->variables);
839}
840
841/*!
842 * \brief Transition a \ref cdr_object to a new state with initiation flag
843 * \param cdr The \ref cdr_object to transition
844 * \param fn_table The \ref cdr_object_fn_table state to go to
845 * \param do_init
846 */
847static void cdr_object_transition_state_init(struct cdr_object *cdr, struct cdr_object_fn_table *fn_table, int do_init)
848{
849 CDR_DEBUG("%p - Transitioning CDR for %s from state %s to %s\n",
850 cdr, cdr->party_a.snapshot->base->name,
851 cdr->fn_table ? cdr->fn_table->name : "NONE", fn_table->name);
852 cdr->fn_table = fn_table;
853
854 if (cdr->fn_table->init_function && do_init) {
855 cdr->fn_table->init_function(cdr);
856 }
857}
858
859/*!
860 * \brief Transition a \ref cdr_object to a new state
861 * \param cdr The \ref cdr_object to transition
862 * \param fn_table The \ref cdr_object_fn_table state to go to
863 */
864static void cdr_object_transition_state(struct cdr_object *cdr, struct cdr_object_fn_table *fn_table)
865{
866 cdr_object_transition_state_init(cdr, fn_table, 1);
867}
868
869/*!
870 * \internal
871 * \brief Hash function for master CDR container indexed by Party A uniqueid.
872 */
873static int cdr_master_hash_fn(const void *obj, const int flags)
874{
875 const struct cdr_object *cdr;
876 const char *key;
877
878 switch (flags & OBJ_SEARCH_MASK) {
879 case OBJ_SEARCH_KEY:
880 key = obj;
881 break;
883 cdr = obj;
884 key = cdr->uniqueid;
885 break;
886 default:
887 ast_assert(0);
888 return 0;
889 }
890 return ast_str_case_hash(key);
891}
892
893/*!
894 * \internal
895 * \brief Comparison function for master CDR container indexed by Party A uniqueid.
896 */
897static int cdr_master_cmp_fn(void *obj, void *arg, int flags)
898{
899 struct cdr_object *left = obj;
900 struct cdr_object *right = arg;
901 const char *right_key = arg;
902 int cmp;
903
904 switch (flags & OBJ_SEARCH_MASK) {
906 right_key = right->uniqueid;
907 /* Fall through */
908 case OBJ_SEARCH_KEY:
909 cmp = strcmp(left->uniqueid, right_key);
910 break;
912 /*
913 * We could also use a partial key struct containing a length
914 * so strlen() does not get called for every comparison instead.
915 */
916 cmp = strncmp(left->uniqueid, right_key, strlen(right_key));
917 break;
918 default:
919 /* Sort can only work on something with a full or partial key. */
920 ast_assert(0);
921 cmp = 0;
922 break;
923 }
924 return cmp ? 0 : CMP_MATCH;
925}
926
927/*!
928 * \internal
929 * \brief Hash function for all CDR container indexed by Party B channel name.
930 */
931static int cdr_all_hash_fn(const void *obj, const int flags)
932{
933 const struct cdr_object *cdr;
934 const char *key;
935
936 switch (flags & OBJ_SEARCH_MASK) {
937 case OBJ_SEARCH_KEY:
938 key = obj;
939 break;
941 cdr = obj;
942 key = cdr->party_b_name;
943 break;
944 default:
945 ast_assert(0);
946 return 0;
947 }
948 return ast_str_case_hash(key);
949}
950
951/*!
952 * \internal
953 * \brief Comparison function for all CDR container indexed by Party B channel name.
954 */
955static int cdr_all_cmp_fn(void *obj, void *arg, int flags)
956{
957 struct cdr_object *left = obj;
958 struct cdr_object *right = arg;
959 const char *right_key = arg;
960 int cmp;
961
962 switch (flags & OBJ_SEARCH_MASK) {
964 right_key = right->party_b_name;
965 /* Fall through */
966 case OBJ_SEARCH_KEY:
967 cmp = strcasecmp(left->party_b_name, right_key);
968 break;
970 /*
971 * We could also use a partial key struct containing a length
972 * so strlen() does not get called for every comparison instead.
973 */
974 cmp = strncasecmp(left->party_b_name, right_key, strlen(right_key));
975 break;
976 default:
977 /* Sort can only work on something with a full or partial key. */
978 ast_assert(0);
979 cmp = 0;
980 break;
981 }
982 return cmp ? 0 : CMP_MATCH;
983}
984
985/*!
986 * \internal
987 * \brief Relink the CDR because Party B's snapshot changed.
988 * \since 13.19.0
989 */
990static void cdr_all_relink(struct cdr_object *cdr)
991{
993 if (cdr->party_b.snapshot) {
994 if (strcasecmp(cdr->party_b_name, cdr->party_b.snapshot->base->name)) {
998 }
999 } else {
1002 }
1004}
1005
1006/*!
1007 * \internal
1008 * \brief Unlink the master CDR and chained records from the active_cdrs_all container.
1009 * \since 13.19.0
1010 */
1011static void cdr_all_unlink(struct cdr_object *cdr)
1012{
1013 struct cdr_object *cur;
1014 struct cdr_object *next;
1015
1016 ast_assert(cdr->is_root);
1017
1018 /* Hold a ref to the root CDR to ensure the list members don't go away on us. */
1019 ao2_ref(cdr, +1);
1021 for (cur = cdr; cur; cur = next) {
1022 next = cur->next;
1024 /*
1025 * It is safe to still use cur after unlinking because the
1026 * root CDR holds a ref to all the CDRs in the list and we
1027 * have a ref to the root CDR.
1028 */
1030 }
1032 ao2_ref(cdr, -1);
1033}
1034
1035/*!
1036 * \brief \ref cdr_object Destructor
1037 */
1038static void cdr_object_dtor(void *obj)
1039{
1040 struct cdr_object *cdr = obj;
1041 struct ast_var_t *it_var;
1042
1045 while ((it_var = AST_LIST_REMOVE_HEAD(&cdr->party_a.variables, entries))) {
1046 ast_var_delete(it_var);
1047 }
1048 while ((it_var = AST_LIST_REMOVE_HEAD(&cdr->party_b.variables, entries))) {
1049 ast_var_delete(it_var);
1050 }
1052
1053 /* CDR destruction used to work by calling ao2_cleanup(next) and
1054 * allowing the chain to destroy itself neatly. Unfortunately, for
1055 * really long chains, this can result in a stack overflow. So now
1056 * when the root CDR is destroyed, it is responsible for unreffing
1057 * all CDRs in the chain
1058 */
1059 if (cdr->is_root) {
1060 struct cdr_object *curr = cdr->next;
1061 struct cdr_object *next;
1062
1063 while (curr) {
1064 next = curr->next;
1065 ao2_cleanup(curr);
1066 curr = next;
1067 }
1068 }
1069}
1070
1071/*!
1072 * \brief \ref cdr_object constructor
1073 * \param chan The \ref ast_channel_snapshot that is the CDR's Party A
1074 * \param event_time
1075 *
1076 * This implicitly sets the state of the newly created CDR to the Single state
1077 * (\ref single_state_fn_table)
1078 */
1079static struct cdr_object *cdr_object_alloc(struct ast_channel_snapshot *chan, const struct timeval *event_time)
1080{
1081 struct cdr_object *cdr;
1082
1083 ast_assert(chan != NULL);
1084
1085 cdr = ao2_alloc(sizeof(*cdr), cdr_object_dtor);
1086 if (!cdr) {
1087 return NULL;
1088 }
1089 cdr->last = cdr;
1090 if (ast_string_field_init(cdr, 64)) {
1091 ao2_cleanup(cdr);
1092 return NULL;
1093 }
1095 ast_string_field_set(cdr, name, chan->base->name);
1099 cdr->lastevent = *event_time;
1100
1101 cdr->party_a.snapshot = chan;
1102 ao2_t_ref(cdr->party_a.snapshot, +1, "bump snapshot during CDR creation");
1103
1104 CDR_DEBUG("%p - Created CDR for channel %s\n", cdr, chan->base->name);
1105
1107
1108 return cdr;
1109}
1110
1111/*!
1112 * \brief Create a new \ref cdr_object and append it to an existing chain
1113 * \param cdr The \ref cdr_object to append to
1114 * \param event_time
1115 */
1116static struct cdr_object *cdr_object_create_and_append(struct cdr_object *cdr, const struct timeval *event_time)
1117{
1118 struct cdr_object *new_cdr;
1119 struct cdr_object *it_cdr;
1120 struct cdr_object *cdr_last;
1121
1122 cdr_last = cdr->last;
1123 new_cdr = cdr_object_alloc(cdr_last->party_a.snapshot, event_time);
1124 if (!new_cdr) {
1125 return NULL;
1126 }
1127 new_cdr->disposition = AST_CDR_NULL;
1128
1129 /* Copy over the linkedid, as it may have changed */
1130 ast_string_field_set(new_cdr, linkedid, cdr_last->linkedid);
1131 ast_string_field_set(new_cdr, appl, cdr_last->appl);
1132 ast_string_field_set(new_cdr, data, cdr_last->data);
1133 ast_string_field_set(new_cdr, context, cdr_last->context);
1134 ast_string_field_set(new_cdr, exten, cdr_last->exten);
1135
1136 /*
1137 * If the current CDR says to disable all future ones,
1138 * keep the disable chain going
1139 */
1140 if (ast_test_flag(&cdr_last->flags, AST_CDR_FLAG_DISABLE_ALL)) {
1142 }
1143
1144 /* Copy over other Party A information */
1145 cdr_object_snapshot_copy(&new_cdr->party_a, &cdr_last->party_a);
1146
1147 /* Append the CDR to the end of the list */
1148 for (it_cdr = cdr; it_cdr->next; it_cdr = it_cdr->next) {
1149 it_cdr->last = new_cdr;
1150 }
1151 it_cdr->last = new_cdr;
1152 it_cdr->next = new_cdr;
1153
1154 return new_cdr;
1155}
1156
1157/*!
1158 * \internal
1159 * \brief Determine if CDR flag is configured.
1160 *
1161 * \param cdr_flag The configured CDR flag to check.
1162 *
1163 * \retval 0 if the CDR flag is not configured.
1164 * \retval non-zero if the CDR flag is configured.
1165 */
1166static int is_cdr_flag_set(unsigned int cdr_flag)
1167{
1168 struct module_config *mod_cfg;
1169 int flag_set;
1170
1171 mod_cfg = ao2_global_obj_ref(module_configs);
1172 flag_set = mod_cfg && ast_test_flag(&mod_cfg->general->settings, cdr_flag);
1173 ao2_cleanup(mod_cfg);
1174 return flag_set;
1175}
1176
1177/*!
1178 * \brief Return whether or not a channel has changed its state in the dialplan, subject
1179 * to endbeforehexten logic
1180 *
1181 * \param old_snapshot The previous state
1182 * \param new_snapshot The new state
1183 *
1184 * \retval 0 if the state has not changed
1185 * \retval 1 if the state changed
1186 */
1187static int snapshot_cep_changed(struct ast_channel_snapshot *old_snapshot,
1188 struct ast_channel_snapshot *new_snapshot)
1189{
1190 /* If we ignore hangup logic, don't indicate that we're executing anything new */
1193 return 0;
1194 }
1195
1196 /* When Party A is originated to an application and the application exits, the stack
1197 * will attempt to clear the application and restore the dummy originate application
1198 * of "AppDialX". Ignore application changes to AppDialX as a result.
1199 */
1200 if (strcmp(new_snapshot->dialplan->appl, old_snapshot->dialplan->appl)
1201 && strncasecmp(new_snapshot->dialplan->appl, "appdial", 7)
1202 && (strcmp(new_snapshot->dialplan->context, old_snapshot->dialplan->context)
1203 || strcmp(new_snapshot->dialplan->exten, old_snapshot->dialplan->exten)
1204 || new_snapshot->dialplan->priority != old_snapshot->dialplan->priority)) {
1205 return 1;
1206 }
1207
1208 return 0;
1209}
1210
1211/*!
1212 * \brief Return whether or not a \ref ast_channel_snapshot is for a channel
1213 * that was created as the result of a dial operation
1214 *
1215 * \retval 0 the channel was not created as the result of a dial
1216 * \retval 1 the channel was created as the result of a dial
1217 */
1218static int snapshot_is_dialed(struct ast_channel_snapshot *snapshot)
1219{
1220 return (ast_test_flag(&snapshot->flags, AST_FLAG_OUTGOING)
1221 && !(ast_test_flag(&snapshot->flags, AST_FLAG_ORIGINATED)));
1222}
1223
1224/*!
1225 * \brief Given two CDR snapshots, figure out who should be Party A for the
1226 * resulting CDR
1227 * \param left One of the snapshots
1228 * \param right The other snapshot
1229 * \return The snapshot that won
1230 */
1232{
1233 /* Check whether or not the party is dialed. A dialed party is never the
1234 * Party A with a party that was not dialed.
1235 */
1236 if (!snapshot_is_dialed(left->snapshot) && snapshot_is_dialed(right->snapshot)) {
1237 return left;
1238 } else if (snapshot_is_dialed(left->snapshot) && !snapshot_is_dialed(right->snapshot)) {
1239 return right;
1240 }
1241
1242 /* Try the Party A flag */
1244 return left;
1246 return right;
1247 }
1248
1249 /* Neither party is dialed and neither has the Party A flag - defer to
1250 * creation time */
1251 if (left->snapshot->base->creationtime.tv_sec < right->snapshot->base->creationtime.tv_sec) {
1252 return left;
1253 } else if (left->snapshot->base->creationtime.tv_sec > right->snapshot->base->creationtime.tv_sec) {
1254 return right;
1255 } else if (left->snapshot->base->creationtime.tv_usec > right->snapshot->base->creationtime.tv_usec) {
1256 return right;
1257 } else {
1258 /* Okay, fine, take the left one */
1259 return left;
1260 }
1261}
1262
1263/*!
1264 * Compute the duration for a \ref cdr_object
1265 */
1266static long cdr_object_get_duration(struct cdr_object *cdr)
1267{
1268 return (long)(ast_tvdiff_ms(ast_tvzero(cdr->end) ? ast_tvnow() : cdr->end, cdr->start) / 1000);
1269}
1270
1271/*!
1272 * \brief Compute the billsec for a \ref cdr_object
1273 */
1274static long cdr_object_get_billsec(struct cdr_object *cdr)
1275{
1276 long int ms;
1277
1278 if (ast_tvzero(cdr->answer)) {
1279 return 0;
1280 }
1281
1282 ms = ast_tvdiff_ms(ast_tvzero(cdr->end) ? ast_tvnow() : cdr->end, cdr->answer);
1283 if (ms % 1000 >= 500
1285 ms = (ms / 1000) + 1;
1286 } else {
1287 ms = ms / 1000;
1288 }
1289
1290 return ms;
1291}
1292
1293/*!
1294 * \internal
1295 * \brief Set a variable on a CDR object
1296 *
1297 * \param headp The header pointer to the variable to set
1298 * \param name The name of the variable
1299 * \param value The value of the variable
1300 */
1301static void set_variable(struct varshead *headp, const char *name, const char *value)
1302{
1303 struct ast_var_t *newvariable;
1304
1305 AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
1306 if (!strcasecmp(ast_var_name(newvariable), name)) {
1308 ast_var_delete(newvariable);
1309 break;
1310 }
1311 }
1313
1314 if (value && (newvariable = ast_var_assign(name, value))) {
1315 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1316 }
1317}
1318
1319/*!
1320 * \brief Create a chain of \ref ast_cdr objects from a chain of \ref cdr_object
1321 * suitable for consumption by the registered CDR backends
1322 * \param cdr The \ref cdr_object to convert to a public record
1323 * \return A chain of \ref ast_cdr objects on success
1324 * \retval NULL on failure
1325 */
1327{
1328 struct ast_cdr *pub_cdr = NULL, *cdr_prev = NULL;
1329 struct cdr_object *it_cdr;
1330 struct ast_var_t *it_var, *it_copy_var;
1331 struct ast_channel_snapshot *party_a;
1332 struct ast_channel_snapshot *party_b;
1333
1334 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
1335 struct ast_cdr *cdr_copy;
1336
1337 /* Don't create records for CDRs where the party A was a dialed channel */
1338 if (snapshot_is_dialed(it_cdr->party_a.snapshot) && !it_cdr->party_b.snapshot) {
1339 ast_debug(1, "CDR for %s is dialed and has no Party B; discarding\n",
1340 it_cdr->party_a.snapshot->base->name);
1341 continue;
1342 }
1343
1344 cdr_copy = ast_calloc(1, sizeof(*cdr_copy));
1345 if (!cdr_copy) {
1346 ast_free(pub_cdr);
1347 return NULL;
1348 }
1349
1350 party_a = it_cdr->party_a.snapshot;
1351 party_b = it_cdr->party_b.snapshot;
1352
1353 /* Party A */
1354 ast_assert(party_a != NULL);
1355 ast_copy_string(cdr_copy->accountcode, party_a->base->accountcode, sizeof(cdr_copy->accountcode));
1356 cdr_copy->amaflags = party_a->amaflags;
1357 ast_copy_string(cdr_copy->channel, party_a->base->name, sizeof(cdr_copy->channel));
1358 ast_callerid_merge(cdr_copy->clid, sizeof(cdr_copy->clid), party_a->caller->name, party_a->caller->number, "");
1359 ast_copy_string(cdr_copy->src, party_a->caller->number, sizeof(cdr_copy->src));
1360 ast_copy_string(cdr_copy->uniqueid, party_a->base->uniqueid, sizeof(cdr_copy->uniqueid));
1361 ast_copy_string(cdr_copy->lastapp, it_cdr->appl, sizeof(cdr_copy->lastapp));
1362 ast_copy_string(cdr_copy->lastdata, it_cdr->data, sizeof(cdr_copy->lastdata));
1363 ast_copy_string(cdr_copy->dst, it_cdr->exten, sizeof(cdr_copy->dst));
1364 ast_copy_string(cdr_copy->dcontext, it_cdr->context, sizeof(cdr_copy->dcontext));
1365
1366 /* Party B */
1367 if (party_b) {
1368 ast_copy_string(cdr_copy->dstchannel, party_b->base->name, sizeof(cdr_copy->dstchannel));
1369 ast_copy_string(cdr_copy->peeraccount, party_b->base->accountcode, sizeof(cdr_copy->peeraccount));
1370 if (!ast_strlen_zero(it_cdr->party_b.userfield)) {
1371 snprintf(cdr_copy->userfield, sizeof(cdr_copy->userfield), "%s;%s", it_cdr->party_a.userfield, it_cdr->party_b.userfield);
1372 }
1373 }
1374 if (ast_strlen_zero(cdr_copy->userfield) && !ast_strlen_zero(it_cdr->party_a.userfield)) {
1375 ast_copy_string(cdr_copy->userfield, it_cdr->party_a.userfield, sizeof(cdr_copy->userfield));
1376 }
1377
1378 /* Timestamps/durations */
1379 cdr_copy->start = it_cdr->start;
1380 cdr_copy->answer = it_cdr->answer;
1381 cdr_copy->end = it_cdr->end;
1382 cdr_copy->billsec = cdr_object_get_billsec(it_cdr);
1383 cdr_copy->duration = cdr_object_get_duration(it_cdr);
1384
1385 /* Flags and IDs */
1386 ast_copy_flags(cdr_copy, &it_cdr->flags, AST_FLAGS_ALL);
1387 ast_copy_string(cdr_copy->linkedid, it_cdr->linkedid, sizeof(cdr_copy->linkedid));
1388 cdr_copy->disposition = it_cdr->disposition;
1389 cdr_copy->sequence = it_cdr->sequence;
1390
1391 /* Variables */
1392 copy_variables(&cdr_copy->varshead, &it_cdr->party_a.variables);
1393 AST_LIST_TRAVERSE(&it_cdr->party_b.variables, it_var, entries) {
1394 int found = 0;
1395 struct ast_var_t *newvariable;
1396 AST_LIST_TRAVERSE(&cdr_copy->varshead, it_copy_var, entries) {
1397 if (!strcasecmp(ast_var_name(it_var), ast_var_name(it_copy_var))) {
1398 found = 1;
1399 break;
1400 }
1401 }
1402 if (!found && (newvariable = ast_var_assign(ast_var_name(it_var), ast_var_value(it_var)))) {
1403 AST_LIST_INSERT_TAIL(&cdr_copy->varshead, newvariable, entries);
1404 }
1405 }
1406
1407 if (!pub_cdr) {
1408 pub_cdr = cdr_copy;
1409 cdr_prev = pub_cdr;
1410 } else {
1411 cdr_prev->next = cdr_copy;
1412 cdr_prev = cdr_copy;
1413 }
1414 }
1415
1416 return pub_cdr;
1417}
1418
1419/*!
1420 * \brief Dispatch a CDR.
1421 * \param cdr The \ref cdr_object to dispatch
1422 *
1423 * This will create a \ref ast_cdr object and publish it to the various backends
1424 */
1425static void cdr_object_dispatch(struct cdr_object *cdr)
1426{
1427 struct ast_cdr *pub_cdr;
1428
1429 CDR_DEBUG("%p - Dispatching CDR for Party A %s, Party B %s\n", cdr,
1430 cdr->party_a.snapshot->base->name,
1431 cdr->party_b.snapshot ? cdr->party_b.snapshot->base->name : "<none>");
1432 pub_cdr = cdr_object_create_public_records(cdr);
1433 cdr_detach(pub_cdr);
1434}
1435
1436/*!
1437 * \brief Set the disposition on a \ref cdr_object based on a hangupcause code
1438 * \param cdr The \ref cdr_object
1439 * \param hangupcause The Asterisk hangup cause code
1440 */
1441static void cdr_object_set_disposition(struct cdr_object *cdr, int hangupcause)
1442{
1443 /* Change the disposition based on the hang up cause */
1444 switch (hangupcause) {
1445 case AST_CAUSE_BUSY:
1447 break;
1451 } else {
1453 }
1454 break;
1458 break;
1462 break;
1463 default:
1464 break;
1465 }
1466}
1467
1468/*!
1469 * \brief Finalize a CDR.
1470 *
1471 * This function is safe to call multiple times. Note that you can call this
1472 * explicitly before going to the finalized state if there's a chance the CDR
1473 * will be re-activated, in which case the \p cdr's end time should be
1474 * cleared. This function is implicitly called when a CDR transitions to the
1475 * finalized state and right before it is dispatched
1476 *
1477 * \param cdr The CDR to finalize
1478 */
1479static void cdr_object_finalize(struct cdr_object *cdr)
1480{
1481 if (!ast_tvzero(cdr->end)) {
1482 return;
1483 }
1484 cdr->end = cdr->lastevent;
1485
1486 if (cdr->disposition == AST_CDR_NULL) {
1487 if (!ast_tvzero(cdr->answer)) {
1489 } else if (cdr->party_a.snapshot->hangup->cause) {
1491 } else if (cdr->party_b.snapshot && cdr->party_b.snapshot->hangup->cause) {
1493 } else {
1495 }
1496 }
1497
1498 /* tv_usec is suseconds_t, which could be int or long */
1499 ast_debug(1, "Finalized CDR for %s - start %ld.%06ld answer %ld.%06ld end %ld.%06ld dur %.3f bill %.3f dispo %s\n",
1500 cdr->party_a.snapshot->base->name,
1501 (long)cdr->start.tv_sec,
1502 (long)cdr->start.tv_usec,
1503 (long)cdr->answer.tv_sec,
1504 (long)cdr->answer.tv_usec,
1505 (long)cdr->end.tv_sec,
1506 (long)cdr->end.tv_usec,
1507 (double)ast_tvdiff_ms(cdr->end, cdr->start) / 1000.0,
1508 (double)ast_tvdiff_ms(cdr->end, cdr->answer) / 1000.0,
1510}
1511
1512/*!
1513 * \brief Check to see if a CDR needs to move to the finalized state because
1514 * its Party A hungup.
1515 */
1517{
1521 }
1522
1524 && cdr->fn_table != &finalized_state_fn_table) {
1526 }
1527}
1528
1529/*!
1530 * \brief Check to see if a CDR needs to be answered based on its Party A.
1531 * Note that this is safe to call as much as you want - we won't answer twice
1532 */
1534{
1535 if (cdr->party_a.snapshot->state == AST_STATE_UP && ast_tvzero(cdr->answer)) {
1536 cdr->answer = cdr->lastevent;
1537 /* tv_usec is suseconds_t, which could be int or long */
1538 CDR_DEBUG("%p - Set answered time to %ld.%06ld\n", cdr,
1539 (long)cdr->answer.tv_sec,
1540 (long)cdr->answer.tv_usec);
1541 }
1542}
1543
1544/*! \brief Set Caller ID information on a CDR */
1545static void cdr_object_update_cid(struct cdr_object_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
1546{
1547 if (!old_snapshot->snapshot) {
1548 set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller->dnid);
1549 set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller->subaddr);
1550 set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->caller->dialed_subaddr);
1551 return;
1552 }
1553 if (strcmp(old_snapshot->snapshot->caller->dnid, new_snapshot->caller->dnid)) {
1554 set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller->dnid);
1555 }
1556 if (strcmp(old_snapshot->snapshot->caller->subaddr, new_snapshot->caller->subaddr)) {
1557 set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller->subaddr);
1558 }
1559 if (strcmp(old_snapshot->snapshot->caller->dialed_subaddr, new_snapshot->caller->dialed_subaddr)) {
1560 set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->caller->dialed_subaddr);
1561 }
1562}
1563
1564/*!
1565 * \brief Swap an old \ref cdr_object_snapshot's \ref ast_channel_snapshot for
1566 * a new \ref ast_channel_snapshot
1567 * \param old_snapshot The old \ref cdr_object_snapshot
1568 * \param new_snapshot The new \ref ast_channel_snapshot for old_snapshot
1569 */
1570static void cdr_object_swap_snapshot(struct cdr_object_snapshot *old_snapshot,
1571 struct ast_channel_snapshot *new_snapshot)
1572{
1573 cdr_object_update_cid(old_snapshot, new_snapshot);
1574 ao2_t_replace(old_snapshot->snapshot, new_snapshot, "Swap CDR shapshot");
1575}
1576
1577/* BASE METHOD IMPLEMENTATIONS */
1578
1579static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
1580{
1581 ast_assert(strcasecmp(snapshot->base->name, cdr->party_a.snapshot->base->name) == 0);
1582
1583 /* Finalize the CDR if we're in hangup logic and we're set to do so */
1587 return 0;
1588 }
1589
1590 /*
1591 * Only record the context and extension if we aren't in a subroutine, or if
1592 * we are executing hangup logic.
1593 */
1596 if (strcmp(cdr->context, snapshot->dialplan->context)) {
1597 ast_string_field_set(cdr, context, snapshot->dialplan->context);
1598 }
1599 if (strcmp(cdr->exten, snapshot->dialplan->exten)) {
1600 ast_string_field_set(cdr, exten, snapshot->dialplan->exten);
1601 }
1602 }
1603
1604 cdr_object_swap_snapshot(&cdr->party_a, snapshot);
1605
1606 /* When Party A is originated to an application and the application exits, the stack
1607 * will attempt to clear the application and restore the dummy originate application
1608 * of "AppDialX". Prevent that, and any other application changes we might not want
1609 * here.
1610 */
1612 && !ast_strlen_zero(snapshot->dialplan->appl)
1613 && (strncasecmp(snapshot->dialplan->appl, "appdial", 7) || ast_strlen_zero(cdr->appl))) {
1614 if (strcmp(cdr->appl, snapshot->dialplan->appl)) {
1615 ast_string_field_set(cdr, appl, snapshot->dialplan->appl);
1616 }
1617 if (strcmp(cdr->data, snapshot->dialplan->data)) {
1618 ast_string_field_set(cdr, data, snapshot->dialplan->data);
1619 }
1620
1621 /* Dial (app_dial) is a special case. Because pre-dial handlers, which
1622 * execute before the dial begins, will alter the application/data to
1623 * something people typically don't want to see, if we see a channel enter
1624 * into Dial here, we set the appl/data accordingly and lock it.
1625 */
1626 if (!strcmp(snapshot->dialplan->appl, "Dial")) {
1628 }
1629 }
1630
1631 if (strcmp(cdr->linkedid, snapshot->peer->linkedid)) {
1632 ast_string_field_set(cdr, linkedid, snapshot->peer->linkedid);
1633 }
1636
1637 return 0;
1638}
1639
1641{
1642 return 0;
1643}
1644
1645static int base_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
1646{
1647 return 0;
1648}
1649
1651{
1652 /* Base process bridge enter simply indicates that we can't handle it */
1653 return BRIDGE_ENTER_NEED_CDR;
1654}
1655
1656static int base_process_parked_channel(struct cdr_object *cdr, struct ast_parked_call_payload *parking_info)
1657{
1658 char park_info[128];
1659
1660 ast_assert(!strcasecmp(parking_info->parkee->base->name, cdr->party_a.snapshot->base->name));
1661
1662 /* Update Party A information regardless */
1663 cdr->fn_table->process_party_a(cdr, parking_info->parkee);
1664
1665 /* Fake out where we're parked */
1666 ast_string_field_set(cdr, appl, "Park");
1667 snprintf(park_info, sizeof(park_info), "%s:%u", parking_info->parkinglot, parking_info->parkingspace);
1668 ast_string_field_set(cdr, data, park_info);
1669
1670 /* Prevent any further changes to the App/Data fields for this record */
1672
1673 return 0;
1674}
1675
1676/* SINGLE STATE */
1677
1679{
1680 cdr->start = cdr->lastevent;
1682}
1683
1684static void single_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
1685{
1686 /* This should never happen! */
1688 ast_assert(0);
1689 return;
1690}
1691
1693{
1694 if (caller && !strcasecmp(cdr->party_a.snapshot->base->name, caller->base->name)) {
1695 base_process_party_a(cdr, caller);
1696 CDR_DEBUG("%p - Updated Party A %s snapshot\n", cdr,
1697 cdr->party_a.snapshot->base->name);
1698 cdr_object_swap_snapshot(&cdr->party_b, peer);
1699 cdr_all_relink(cdr);
1700 CDR_DEBUG("%p - Updated Party B %s snapshot\n", cdr,
1701 cdr->party_b.snapshot->base->name);
1702
1703 /* If we have two parties, lock the application that caused the
1704 * two parties to be associated. This prevents mid-call event
1705 * gosubs from perturbing the CDR application/data
1706 */
1708 } else if (!strcasecmp(cdr->party_a.snapshot->base->name, peer->base->name)) {
1709 /* We're the entity being dialed, i.e., outbound origination */
1710 base_process_party_a(cdr, peer);
1711 CDR_DEBUG("%p - Updated Party A %s snapshot\n", cdr,
1712 cdr->party_a.snapshot->base->name);
1713 }
1714
1716 return 0;
1717}
1718
1719/*!
1720 * \brief Handle a comparison between our \ref cdr_object and a \ref cdr_object
1721 * already in the bridge while in the Single state. The goal of this is to find
1722 * a Party B for our CDR.
1723 *
1724 * \param cdr Our \ref cdr_object in the Single state
1725 * \param cand_cdr The \ref cdr_object already in the Bridge state
1726 *
1727 * \retval 0 The cand_cdr had a Party A or Party B that we could use as our
1728 * Party B
1729 * \retval 1 No party in the cand_cdr could be used as our Party B
1730 */
1732 struct cdr_object *cand_cdr)
1733{
1734 struct cdr_object_snapshot *party_a;
1735
1736 /* Don't match on ourselves */
1737 if (!strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)) {
1738 return 1;
1739 }
1740
1741 /* Try the candidate CDR's Party A first */
1742 party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
1743 if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
1744 CDR_DEBUG("%p - Party A %s has new Party B %s\n",
1745 cdr, cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name);
1746 cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
1747 cdr_all_relink(cdr);
1748 if (!cand_cdr->party_b.snapshot) {
1749 /* We just stole them - finalize their CDR. Note that this won't
1750 * transition their state, it just sets the end time and the
1751 * disposition - if we need to re-activate them later, we can.
1752 */
1753 cdr_object_finalize(cand_cdr);
1754 }
1755 return 0;
1756 }
1757
1758 /* Try their Party B, unless it's us */
1759 if (!cand_cdr->party_b.snapshot
1760 || !strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_b.snapshot->base->name)) {
1761 return 1;
1762 }
1763 party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_b);
1764 if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
1765 CDR_DEBUG("%p - Party A %s has new Party B %s\n",
1766 cdr, cdr->party_a.snapshot->base->name, cand_cdr->party_b.snapshot->base->name);
1767 cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_b);
1768 cdr_all_relink(cdr);
1769 return 0;
1770 }
1771
1772 return 1;
1773}
1774
1776{
1777 struct ao2_iterator it_cdrs;
1778 char *channel_id;
1779 int success = 0;
1780
1781 ast_string_field_set(cdr, bridge, bridge->uniqueid);
1782
1783 if (ao2_container_count(bridge->channels) == 1) {
1784 /* No one in the bridge yet but us! */
1787 }
1788
1789 for (it_cdrs = ao2_iterator_init(bridge->channels, 0);
1790 !success && (channel_id = ao2_iterator_next(&it_cdrs));
1791 ao2_ref(channel_id, -1)) {
1792 struct cdr_object *cand_cdr_master;
1793 struct cdr_object *cand_cdr;
1794
1795 cand_cdr_master = ao2_find(active_cdrs_master, channel_id, OBJ_SEARCH_KEY);
1796 if (!cand_cdr_master) {
1797 continue;
1798 }
1799
1800 ao2_lock(cand_cdr_master);
1801 for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->next) {
1802 /* Skip any records that are not in a bridge or in this bridge.
1803 * I'm not sure how that would happen, but it pays to be careful. */
1804 if (cand_cdr->fn_table != &bridge_state_fn_table ||
1805 strcmp(cdr->bridge, cand_cdr->bridge)) {
1806 continue;
1807 }
1808
1809 if (single_state_bridge_enter_comparison(cdr, cand_cdr)) {
1810 continue;
1811 }
1812 /* We successfully got a party B - break out */
1813 success = 1;
1814 break;
1815 }
1816 ao2_unlock(cand_cdr_master);
1817 ao2_cleanup(cand_cdr_master);
1818 }
1819 ao2_iterator_destroy(&it_cdrs);
1820
1821 /* We always transition state, even if we didn't get a peer */
1823
1824 /* Success implies that we have a Party B */
1825 if (success) {
1827 }
1828
1830}
1831
1833{
1835 return 0;
1836}
1837
1838
1839/* DIAL STATE */
1840
1841static void dial_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
1842{
1843 ast_assert(snapshot != NULL);
1845 && !strcasecmp(cdr->party_b.snapshot->base->name, snapshot->base->name));
1846
1847 cdr_object_swap_snapshot(&cdr->party_b, snapshot);
1848
1849 /* If party B hangs up, finalize this CDR */
1852 }
1853}
1854
1855static int dial_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
1856{
1857 /* Don't process a begin dial here. A party A already in the dial state will
1858 * who receives a dial begin for something else will be handled by the
1859 * message router callback and will add a new CDR for the party A */
1860 return 1;
1861}
1862
1863/*!
1864 * \internal
1865 * \brief Convert a dial status to a CDR disposition
1866 */
1867static enum ast_cdr_disposition dial_status_to_disposition(const char *dial_status)
1868{
1869 if (!strcmp(dial_status, "ANSWER")) {
1870 return AST_CDR_ANSWERED;
1871 } else if (!strcmp(dial_status, "BUSY")) {
1872 return AST_CDR_BUSY;
1873 } else if (!strcmp(dial_status, "CANCEL") || !strcmp(dial_status, "NOANSWER")) {
1874 return AST_CDR_NOANSWER;
1875 } else if (!strcmp(dial_status, "CONGESTION")) {
1877 return AST_CDR_FAILED;
1878 } else {
1879 return AST_CDR_CONGESTION;
1880 }
1881 } else if (!strcmp(dial_status, "FAILED")) {
1882 return AST_CDR_FAILED;
1883 }
1884 return AST_CDR_FAILED;
1885}
1886
1887static int dial_state_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
1888{
1889 struct ast_channel_snapshot *party_a;
1890
1891 if (caller) {
1892 party_a = caller;
1893 } else {
1894 party_a = peer;
1895 }
1896 ast_assert(!strcasecmp(cdr->party_a.snapshot->base->name, party_a->base->name));
1897 cdr_object_swap_snapshot(&cdr->party_a, party_a);
1898
1899 if (cdr->party_b.snapshot) {
1900 if (strcasecmp(cdr->party_b.snapshot->base->name, peer->base->name)) {
1901 /* Not the status for this CDR - defer back to the message router */
1902 return 1;
1903 }
1905 }
1906
1907 /* Set the disposition based on the dial string. */
1908 cdr->disposition = dial_status_to_disposition(dial_status);
1909 if (cdr->disposition == AST_CDR_ANSWERED) {
1910 /* Switch to dial pending to wait and see what the caller does */
1912 } else {
1914 }
1915
1916 return 0;
1917}
1918
1920{
1921 int success = 0;
1922
1923 ast_string_field_set(cdr, bridge, bridge->uniqueid);
1924
1925 /* Get parties in the bridge */
1926 if (ao2_container_count(bridge->channels) == 1) {
1927 /* No one in the bridge yet but us! */
1930 }
1931
1932 /* If we don't have a Party B (originated channel), skip it */
1933 if (cdr->party_b.snapshot) {
1934 struct ao2_iterator it_cdrs;
1935 char *channel_id;
1936
1937 for (it_cdrs = ao2_iterator_init(bridge->channels, 0);
1938 !success && (channel_id = ao2_iterator_next(&it_cdrs));
1939 ao2_ref(channel_id, -1)) {
1940 struct cdr_object *cand_cdr_master;
1941 struct cdr_object *cand_cdr;
1942
1943 cand_cdr_master = ao2_find(active_cdrs_master, channel_id, OBJ_SEARCH_KEY);
1944 if (!cand_cdr_master) {
1945 continue;
1946 }
1947
1948 ao2_lock(cand_cdr_master);
1949 for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->next) {
1950 /* Skip any records that are not in a bridge or in this bridge.
1951 * I'm not sure how that would happen, but it pays to be careful. */
1952 if (cand_cdr->fn_table != &bridge_state_fn_table
1953 || strcmp(cdr->bridge, cand_cdr->bridge)) {
1954 continue;
1955 }
1956
1957 /* Skip any records that aren't our Party B */
1958 if (strcasecmp(cdr->party_b.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)) {
1959 continue;
1960 }
1961 cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
1962 /* If they have a Party B, they joined up with someone else as their
1963 * Party A. Don't finalize them as they're active. Otherwise, we
1964 * have stolen them so they need to be finalized.
1965 */
1966 if (!cand_cdr->party_b.snapshot) {
1967 cdr_object_finalize(cand_cdr);
1968 }
1969 success = 1;
1970 break;
1971 }
1972 ao2_unlock(cand_cdr_master);
1973 ao2_cleanup(cand_cdr_master);
1974 }
1975 ao2_iterator_destroy(&it_cdrs);
1976 }
1977
1978 /* We always transition state, even if we didn't get a peer */
1980
1981 /* Success implies that we have a Party B */
1982 if (success) {
1984 }
1986}
1987
1988/* DIALED PENDING STATE */
1989
1991{
1992 /* If we get a CEP change, we're executing dialplan. If we have a Party B
1993 * that means we need a new CDR; otherwise, switch us over to single.
1994 */
1995 if (snapshot_cep_changed(cdr->party_a.snapshot, snapshot)) {
1996 if (cdr->party_b.snapshot) {
1998 cdr->fn_table->process_party_a(cdr, snapshot);
1999 return 1;
2000 } else {
2001 /* The CDR does not need to be reinitialized when transitioning
2002 * to its single state as this would overwrite the start time,
2003 * causing potentially both the answer and the start time to be
2004 * the same which is incorrect.
2005 */
2007 cdr->fn_table->process_party_a(cdr, snapshot);
2008 return 0;
2009 }
2010 }
2011 base_process_party_a(cdr, snapshot);
2012 return 0;
2013}
2014
2016{
2018 return cdr->fn_table->process_bridge_enter(cdr, bridge, channel);
2019}
2020
2022{
2023 if (cdr->party_b.snapshot) {
2024 /* We can't handle this as we have a Party B - ask for a new one */
2025 return 1;
2026 }
2028 return 0;
2029}
2030
2032{
2034
2035 /* Ask for a new CDR */
2036 return 1;
2037}
2038
2039/* BRIDGE STATE */
2040
2041static void bridge_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
2042{
2044 && !strcasecmp(cdr->party_b.snapshot->base->name, snapshot->base->name));
2045
2046 cdr_object_swap_snapshot(&cdr->party_b, snapshot);
2047
2048 /* If party B hangs up, finalize this CDR */
2051 }
2052}
2053
2055{
2056 if (strcmp(cdr->bridge, bridge->uniqueid)) {
2057 return 1;
2058 }
2059 if (strcasecmp(cdr->party_a.snapshot->base->name, channel->base->name)
2060 && cdr->party_b.snapshot
2061 && strcasecmp(cdr->party_b.snapshot->base->name, channel->base->name)) {
2062 return 1;
2063 }
2065
2066 return 0;
2067}
2068
2069/* PARKED STATE */
2070
2072{
2073 if (strcasecmp(cdr->party_a.snapshot->base->name, channel->base->name)) {
2074 return 1;
2075 }
2077
2078 return 0;
2079}
2080
2081/* FINALIZED STATE */
2082
2084{
2086}
2087
2088static int finalized_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
2089{
2092 return 0;
2093 }
2094
2095 /* Indicate that, if possible, we should get a new CDR */
2096 return 1;
2097}
2098
2099/*!
2100 * \internal
2101 * \brief Filter channel snapshots by technology
2102 */
2104{
2105 return snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL;
2106}
2107
2108/*!
2109 * \internal
2110 * \brief Filter a channel snapshot update
2111 */
2113 struct ast_channel_snapshot *new_snapshot)
2114{
2115 int ret = 0;
2116
2117 /* Drop cache updates from certain channel technologies */
2118 if (old_snapshot) {
2119 ret |= filter_channel_snapshot(old_snapshot);
2120 }
2121 if (new_snapshot) {
2122 ret |= filter_channel_snapshot(new_snapshot);
2123 }
2124
2125 return ret;
2126}
2127
2128static int dial_status_end(const char *dialstatus)
2129{
2130 return (strcmp(dialstatus, "RINGING") &&
2131 strcmp(dialstatus, "PROCEEDING") &&
2132 strcmp(dialstatus, "PROGRESS"));
2133}
2134
2135/* TOPIC ROUTER CALLBACKS */
2136
2137/*!
2138 * \brief Handler for Stasis-Core dial messages
2139 * \param data Passed on
2140 * \param sub The stasis subscription for this message callback
2141 * \param message The message
2142 */
2144{
2145 struct cdr_object *cdr;
2148 struct ast_channel_snapshot *peer;
2149 struct cdr_object *it_cdr;
2150 struct ast_json *dial_status_blob;
2151 const char *dial_status = NULL;
2152 int res = 1;
2153
2154 caller = ast_multi_channel_blob_get_channel(payload, "caller");
2155 peer = ast_multi_channel_blob_get_channel(payload, "peer");
2156 if (!peer && !caller) {
2157 return;
2158 }
2159
2160 if (peer && filter_channel_snapshot(peer)) {
2161 return;
2162 }
2163
2164 if (caller && filter_channel_snapshot(caller)) {
2165 return;
2166 }
2167
2168 dial_status_blob = ast_json_object_get(ast_multi_channel_blob_get_json(payload), "dialstatus");
2169 if (dial_status_blob) {
2170 dial_status = ast_json_string_get(dial_status_blob);
2171 }
2172
2173 CDR_DEBUG("Dial %s message for %s, %s: %u.%08u\n",
2174 ast_strlen_zero(dial_status) ? "Begin" : "End",
2175 caller ? caller->base->name : "(none)",
2176 peer ? peer->base->name : "(none)",
2177 (unsigned int)stasis_message_timestamp(message)->tv_sec,
2178 (unsigned int)stasis_message_timestamp(message)->tv_usec);
2179
2180 /* Figure out who is running this show */
2181 if (caller) {
2183 } else {
2185 }
2186 if (!cdr) {
2187 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", caller ? caller->base->name : peer->base->name);
2188 ast_assert(0);
2189 return;
2190 }
2191
2192 ao2_lock(cdr);
2193 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2195 if (ast_strlen_zero(dial_status)) {
2196 if (!it_cdr->fn_table->process_dial_begin) {
2197 continue;
2198 }
2200 CDR_DEBUG("%p - Ignoring Dial Begin message\n", it_cdr);
2201 continue;
2202 }
2203 CDR_DEBUG("%p - Processing Dial Begin message for channel %s, peer %s\n",
2204 it_cdr,
2205 caller ? caller->base->name : "(none)",
2206 peer ? peer->base->name : "(none)");
2207 res &= it_cdr->fn_table->process_dial_begin(it_cdr,
2208 caller,
2209 peer);
2210 } else if (dial_status_end(dial_status)) {
2211 if (!it_cdr->fn_table->process_dial_end) {
2212 continue;
2213 }
2215 /* Set the disposition, and do nothing else. */
2216 it_cdr->disposition = dial_status_to_disposition(dial_status);
2217 CDR_DEBUG("%p - Setting disposition and that's it (%s)\n", it_cdr, dial_status);
2218 continue;
2219 }
2220 CDR_DEBUG("%p - Processing Dial End message for channel %s, peer %s\n",
2221 it_cdr,
2222 caller ? caller->base->name : "(none)",
2223 peer ? peer->base->name : "(none)");
2224 it_cdr->fn_table->process_dial_end(it_cdr,
2225 caller,
2226 peer,
2227 dial_status);
2228 }
2229 }
2230
2231 /* If we're ignoring dial changes, don't allow multiple CDRs for this channel. */
2232 if (!dial_changes_ignored) {
2233 /* If no CDR handled a dial begin message, make a new one */
2234 if (res && ast_strlen_zero(dial_status)) {
2235 struct cdr_object *new_cdr;
2236
2238 if (new_cdr) {
2239 new_cdr->fn_table->process_dial_begin(new_cdr, caller, peer);
2240 }
2241 }
2242 }
2243
2244 ao2_unlock(cdr);
2245 ao2_cleanup(cdr);
2246}
2247
2248static int cdr_object_finalize_party_b(void *obj, void *arg, void *data, int flags)
2249{
2250 struct cdr_object *cdr = obj;
2251
2252 if (!strcasecmp(cdr->party_b_name, arg)) {
2253#ifdef AST_DEVMODE
2254 struct ast_channel_snapshot *party_b = data;
2255
2256 /*
2257 * For sanity's sake we also assert the party_b snapshot
2258 * is consistent with the key.
2259 */
2261 && !strcasecmp(cdr->party_b.snapshot->base->name, party_b->base->name));
2262#endif
2263
2264 /* Don't transition to the finalized state - let the Party A do
2265 * that when its ready
2266 */
2268 }
2269 return 0;
2270}
2271
2272static int cdr_object_update_party_b(void *obj, void *arg, void *data, int flags)
2273{
2274 struct cdr_object *cdr = obj;
2275
2276 if (cdr->fn_table->process_party_b
2277 && !strcasecmp(cdr->party_b_name, arg)) {
2278 struct ast_channel_snapshot *party_b = data;
2279
2280 /*
2281 * For sanity's sake we also check the party_b snapshot
2282 * for consistency with the key. The callback needs and
2283 * asserts the snapshot to be this way.
2284 */
2285 if (!cdr->party_b.snapshot
2286 || strcasecmp(cdr->party_b.snapshot->base->name, party_b->base->name)) {
2288 "CDR for Party A %s(%s) has inconsistent Party B %s name. Message can be ignored but this shouldn't happen.\n",
2289 cdr->linkedid,
2290 cdr->party_a.snapshot->base->name,
2291 cdr->party_b_name);
2292 return 0;
2293 }
2294
2295 cdr->fn_table->process_party_b(cdr, party_b);
2296 }
2297 return 0;
2298}
2299
2300/*! \brief Determine if we need to add a new CDR based on snapshots */
2301static int check_new_cdr_needed(struct ast_channel_snapshot *old_snapshot,
2302 struct ast_channel_snapshot *new_snapshot)
2303{
2304 /* If we're dead, we don't need a new CDR */
2305 if (!new_snapshot
2308 return 0;
2309 }
2310
2311 /* Auto-fall through will increment the priority but have no application */
2312 if (ast_strlen_zero(new_snapshot->dialplan->appl)) {
2313 return 0;
2314 }
2315
2316 if (old_snapshot && !snapshot_cep_changed(old_snapshot, new_snapshot)) {
2317 return 0;
2318 }
2319
2320 return 1;
2321}
2322
2323/*!
2324 * \brief Handler for channel snapshot update messages
2325 * \param data Passed on
2326 * \param sub The stasis subscription for this message callback
2327 * \param message The message
2328 */
2330{
2331 struct cdr_object *cdr;
2333 struct cdr_object *it_cdr;
2334
2335 if (filter_channel_snapshot_message(update->old_snapshot, update->new_snapshot)) {
2336 return;
2337 }
2338
2339 if (update->new_snapshot && !update->old_snapshot) {
2340 struct module_config *mod_cfg = NULL;
2341
2343 if (!cdr) {
2344 return;
2345 }
2346 mod_cfg = ao2_global_obj_ref(module_configs);
2347 cdr->is_root = 1;
2349
2350 /* If CDR should be disabled unless enabled on a per-channel basis, then disable
2351 CDR, right from the get go */
2352 if (mod_cfg) {
2354 ast_debug(3, "Disable CDR by default\n");
2356 }
2357 ao2_cleanup(mod_cfg);
2358 }
2359 } else {
2360 cdr = ao2_find(active_cdrs_master, update->new_snapshot->base->uniqueid, OBJ_SEARCH_KEY);
2361 }
2362
2363 /* Handle Party A */
2364 if (!cdr) {
2365 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", update->new_snapshot->base->name);
2366 ast_assert(0);
2367 } else {
2368 int all_reject = 1;
2369
2370 ao2_lock(cdr);
2371 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2373 if (!it_cdr->fn_table->process_party_a) {
2374 continue;
2375 }
2376 all_reject &= it_cdr->fn_table->process_party_a(it_cdr, update->new_snapshot);
2377 }
2378 if (all_reject && check_new_cdr_needed(update->old_snapshot, update->new_snapshot)) {
2379 /* We're not hung up and we have a new snapshot - we need a new CDR */
2380 struct cdr_object *new_cdr;
2381
2383 if (new_cdr) {
2384 new_cdr->fn_table->process_party_a(new_cdr, update->new_snapshot);
2385 }
2386 }
2387 ao2_unlock(cdr);
2388 }
2389
2390 if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
2391 ao2_lock(cdr);
2392 CDR_DEBUG("%p - Beginning finalize/dispatch for %s\n", cdr, update->old_snapshot->base->name);
2393 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2395 cdr_object_finalize(it_cdr);
2396 }
2398 ao2_unlock(cdr);
2399
2400 cdr_all_unlink(cdr);
2402 }
2403
2404 /* Handle Party B */
2405 if (update->new_snapshot) {
2407 cdr_object_update_party_b, (char *) update->new_snapshot->base->name, update->new_snapshot);
2408 }
2409
2410 if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
2412 cdr_object_finalize_party_b, (char *) update->new_snapshot->base->name, update->new_snapshot);
2413 }
2414
2415 ao2_cleanup(cdr);
2416}
2417
2421 const struct timeval *lastevent;
2422};
2423
2424/*! \brief Callback used to notify CDRs of a Party B leaving the bridge */
2425static int cdr_object_party_b_left_bridge_cb(void *obj, void *arg, void *data, int flags)
2426{
2427 struct cdr_object *cdr = obj;
2428 struct bridge_leave_data *leave_data = data;
2429
2430 if (cdr->fn_table == &bridge_state_fn_table
2431 && !strcmp(cdr->bridge, leave_data->bridge->uniqueid)
2432 && !strcasecmp(cdr->party_b_name, arg)) {
2433 /*
2434 * For sanity's sake we also assert the party_b snapshot
2435 * is consistent with the key.
2436 */
2438 && !strcasecmp(cdr->party_b.snapshot->base->name, leave_data->channel->base->name));
2439
2440 /* It is our Party B, in our bridge. Set the last event and let the handler
2441 * transition our CDR appropriately when we leave the bridge.
2442 */
2443 cdr->lastevent = *leave_data->lastevent;
2445 }
2446 return 0;
2447}
2448
2449/*! \brief Filter bridge messages based on bridge technology */
2451{
2452 /* Ignore holding bridge technology messages. We treat this simply as an application
2453 * that a channel enters into.
2454 */
2455 if (!strcmp(bridge->technology, "holding_bridge") && strcmp(bridge->subclass, "parking")) {
2456 return 1;
2457 }
2458 return 0;
2459}
2460
2461/*!
2462 * \brief Handler for when a channel leaves a bridge
2463 * \param data Passed on
2464 * \param sub The stasis subscription for this message callback
2465 * \param message The message - hopefully a bridge one!
2466 */
2468 struct stasis_message *message)
2469{
2471 struct ast_bridge_snapshot *bridge = update->bridge;
2472 struct ast_channel_snapshot *channel = update->channel;
2473 struct cdr_object *cdr;
2474 struct cdr_object *it_cdr;
2475 struct bridge_leave_data leave_data = {
2476 .bridge = bridge,
2477 .channel = channel,
2478 .lastevent = stasis_message_timestamp(message)
2479 };
2480 int left_bridge = 0;
2481
2483 return;
2484 }
2485
2487 return;
2488 }
2489
2490 CDR_DEBUG("Bridge Leave message for %s: %u.%08u\n",
2491 channel->base->name,
2492 (unsigned int)leave_data.lastevent->tv_sec,
2493 (unsigned int)leave_data.lastevent->tv_usec);
2494
2496 if (!cdr) {
2497 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
2498 ast_assert(0);
2499 return;
2500 }
2501
2502 /* Party A */
2503 ao2_lock(cdr);
2504 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2505 it_cdr->lastevent = *leave_data.lastevent;
2506 if (!it_cdr->fn_table->process_bridge_leave) {
2507 continue;
2508 }
2509 CDR_DEBUG("%p - Processing Bridge Leave for %s\n",
2510 it_cdr, channel->base->name);
2511 if (!it_cdr->fn_table->process_bridge_leave(it_cdr, bridge, channel)) {
2512 ast_string_field_set(it_cdr, bridge, "");
2513 left_bridge = 1;
2514 }
2515 }
2516 ao2_unlock(cdr);
2517
2518 /* Party B */
2519 if (left_bridge
2520 && strcmp(bridge->subclass, "parking")) {
2522 cdr_object_party_b_left_bridge_cb, (char *) leave_data.channel->base->name,
2523 &leave_data);
2524 }
2525
2526 ao2_cleanup(cdr);
2527}
2528
2529/*!
2530 * \internal
2531 * \brief Create a new CDR, append it to an existing CDR, and update its snapshots
2532 *
2533 * \note The new CDR will be automatically transitioned to the bridge state
2534 */
2536 struct cdr_object_snapshot *party_b)
2537{
2538 struct cdr_object *new_cdr;
2539
2540 new_cdr = cdr_object_create_and_append(cdr, &cdr->lastevent);
2541 if (!new_cdr) {
2542 return;
2543 }
2545 cdr_all_relink(new_cdr);
2547 ast_string_field_set(new_cdr, bridge, cdr->bridge);
2549 CDR_DEBUG("%p - Party A %s has new Party B %s\n",
2550 new_cdr, new_cdr->party_a.snapshot->base->name,
2552}
2553
2554/*!
2555 * \brief Process a single \c bridge_candidate
2556 *
2557 * When a CDR enters a bridge, it needs to make pairings with everyone else
2558 * that it is not currently paired with. This function determines, for the
2559 * CDR for the channel that entered the bridge and the CDR for every other
2560 * channel currently in the bridge, who is Party A and makes new CDRs.
2561 *
2562 * \param cdr The \ref cdr_object being processed
2563 * \param base_cand_cdr The \ref cdr_object that is a candidate
2564 *
2565 */
2566static void bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *base_cand_cdr)
2567{
2568 struct cdr_object_snapshot *party_a;
2569 struct cdr_object *cand_cdr;
2570
2571 ao2_lock(base_cand_cdr);
2572
2573 for (cand_cdr = base_cand_cdr; cand_cdr; cand_cdr = cand_cdr->next) {
2574 /* Skip any records that are not in this bridge */
2575 if (strcmp(cand_cdr->bridge, cdr->bridge)) {
2576 continue;
2577 }
2578
2579 /* If the candidate is us or someone we've taken on, pass on by */
2580 if (!strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)
2581 || (cdr->party_b.snapshot
2582 && !strcasecmp(cdr->party_b.snapshot->base->name, cand_cdr->party_a.snapshot->base->name))) {
2583 break;
2584 }
2585
2586 party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
2587 /* We're party A - make a new CDR, append it to us, and set the candidate as
2588 * Party B */
2589 if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
2590 bridge_candidate_add_to_cdr(cdr, &cand_cdr->party_a);
2591 break;
2592 }
2593
2594 /* We're Party B. Check if we can add ourselves immediately or if we need
2595 * a new CDR for them (they already have a Party B) */
2596 if (cand_cdr->party_b.snapshot
2597 && strcasecmp(cand_cdr->party_b.snapshot->base->name, cdr->party_a.snapshot->base->name)) {
2598 bridge_candidate_add_to_cdr(cand_cdr, &cdr->party_a);
2599 } else {
2600 CDR_DEBUG("%p - Party A %s has new Party B %s\n",
2601 cand_cdr, cand_cdr->party_a.snapshot->base->name,
2602 cdr->party_a.snapshot->base->name);
2603 cdr_object_snapshot_copy(&cand_cdr->party_b, &cdr->party_a);
2604 cdr_all_relink(cand_cdr);
2605 /* It's possible that this joined at one point and was never chosen
2606 * as party A. Clear their end time, as it would be set in such a
2607 * case.
2608 */
2609 memset(&cand_cdr->end, 0, sizeof(cand_cdr->end));
2610 }
2611
2612 break;
2613 }
2614
2615 ao2_unlock(base_cand_cdr);
2616}
2617
2618/*!
2619 * \brief Handle creating bridge pairings for the \ref cdr_object that just
2620 * entered a bridge
2621 * \param cdr The \ref cdr_object that just entered the bridge
2622 * \param bridge The \ref ast_bridge_snapshot representing the bridge it just entered
2623 */
2625{
2626 struct ao2_iterator it_channels;
2627 char *channel_id;
2628
2629 it_channels = ao2_iterator_init(bridge->channels, 0);
2630 while ((channel_id = ao2_iterator_next(&it_channels))) {
2631 struct cdr_object *cand_cdr;
2632
2633 cand_cdr = ao2_find(active_cdrs_master, channel_id, OBJ_SEARCH_KEY);
2634 if (cand_cdr) {
2635 bridge_candidate_process(cdr, cand_cdr);
2636 ao2_ref(cand_cdr, -1);
2637 }
2638
2639 ao2_ref(channel_id, -1);
2640 }
2641 ao2_iterator_destroy(&it_channels);
2642}
2643
2644/*! \brief Handle entering into a parking bridge
2645 * \param cdr The CDR to operate on
2646 * \param bridge The bridge the channel just entered
2647 * \param channel The channel snapshot
2648 * \param event_time
2649 */
2652 struct ast_channel_snapshot *channel,
2653 const struct timeval *event_time)
2654{
2655 int res = 1;
2656 struct cdr_object *it_cdr;
2657 struct cdr_object *new_cdr;
2658
2659 ao2_lock(cdr);
2660
2661 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2662 it_cdr->lastevent = *event_time;
2663
2665 res &= it_cdr->fn_table->process_parking_bridge_enter(it_cdr, bridge, channel);
2666 }
2667 if (it_cdr->fn_table->process_party_a) {
2668 CDR_DEBUG("%p - Updating Party A %s snapshot\n", it_cdr,
2669 channel->base->name);
2670 it_cdr->fn_table->process_party_a(it_cdr, channel);
2671 }
2672 }
2673
2674 if (res) {
2675 /* No one handled it - we need a new one! */
2676 new_cdr = cdr_object_create_and_append(cdr, event_time);
2677 if (new_cdr) {
2678 /* Let the single state transition us to Parked */
2680 new_cdr->fn_table->process_parking_bridge_enter(new_cdr, bridge, channel);
2681 }
2682 }
2683 ao2_unlock(cdr);
2684}
2685
2686/*! \brief Handle a bridge enter message for a 'normal' bridge
2687 * \param cdr The CDR to operate on
2688 * \param bridge The bridge the channel just entered
2689 * \param channel The channel snapshot
2690 * \param event_time
2691 */
2694 struct ast_channel_snapshot *channel,
2695 const struct timeval *event_time)
2696{
2698 struct cdr_object *it_cdr;
2699 struct cdr_object *new_cdr;
2700 struct cdr_object *handled_cdr = NULL;
2701
2702 ao2_lock(cdr);
2703
2704try_again:
2705 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2706 it_cdr->lastevent = *event_time;
2707
2708 if (it_cdr->fn_table->process_party_a) {
2709 CDR_DEBUG("%p - Updating Party A %s snapshot\n", it_cdr,
2710 channel->base->name);
2711 it_cdr->fn_table->process_party_a(it_cdr, channel);
2712 }
2713
2714 /* Notify all states that they have entered a bridge */
2715 if (it_cdr->fn_table->process_bridge_enter) {
2716 CDR_DEBUG("%p - Processing bridge enter for %s\n", it_cdr,
2717 channel->base->name);
2718 result = it_cdr->fn_table->process_bridge_enter(it_cdr, bridge, channel);
2719 switch (result) {
2721 /* Fall through */
2723 if (!handled_cdr) {
2724 handled_cdr = it_cdr;
2725 }
2726 break;
2728 /* Pass */
2729 break;
2731 /* We didn't win on any - end this CDR. If someone else comes in later
2732 * that is Party B to this CDR, it can re-activate this CDR.
2733 */
2734 if (!handled_cdr) {
2735 handled_cdr = it_cdr;
2736 }
2738 break;
2739 }
2740 }
2741 }
2742
2743 /* Create the new matchings, but only for either:
2744 * * The first CDR in the chain that handled it. This avoids issues with
2745 * forked CDRs.
2746 * * If no one handled it, the last CDR in the chain. This would occur if
2747 * a CDR joined a bridge and it wasn't Party A for anyone. We still need
2748 * to make pairings with everyone in the bridge.
2749 */
2750 if (handled_cdr) {
2751 handle_bridge_pairings(handled_cdr, bridge);
2752 } else {
2753 /* Nothing handled it - we need a new one! */
2754 new_cdr = cdr_object_create_and_append(cdr, event_time);
2755 if (new_cdr) {
2756 /* This is guaranteed to succeed: the new CDR is created in the single state
2757 * and will be able to handle the bridge enter message
2758 */
2759 goto try_again;
2760 }
2761 }
2762 ao2_unlock(cdr);
2763}
2764
2765/*!
2766 * \internal
2767 * \brief Handler for Stasis-Core bridge enter messages
2768 * \param data Passed on
2769 * \param sub The stasis subscription for this message callback
2770 * \param message The message - hopefully a bridge one!
2771 */
2773 struct stasis_message *message)
2774{
2776 struct ast_bridge_snapshot *bridge = update->bridge;
2777 struct ast_channel_snapshot *channel = update->channel;
2778 struct cdr_object *cdr;
2779
2781 return;
2782 }
2783
2784 if (filter_channel_snapshot(channel)) {
2785 return;
2786 }
2787
2788 CDR_DEBUG("Bridge Enter message for channel %s: %u.%08u\n",
2789 channel->base->name,
2790 (unsigned int)stasis_message_timestamp(message)->tv_sec,
2791 (unsigned int)stasis_message_timestamp(message)->tv_usec);
2792
2794 if (!cdr) {
2795 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
2796 ast_assert(0);
2797 return;
2798 }
2799
2800 if (!strcmp(bridge->subclass, "parking")) {
2802 } else {
2804 }
2805 ao2_cleanup(cdr);
2806}
2807
2808/*!
2809 * \brief Handler for when a channel is parked
2810 * \param data Passed on
2811 * \param sub The stasis subscription for this message callback
2812 * \param message The message about who got parked
2813 * */
2815 struct stasis_message *message)
2816{
2818 struct ast_channel_snapshot *channel = payload->parkee;
2819 struct cdr_object *cdr;
2820 int unhandled = 1;
2821 struct cdr_object *it_cdr;
2822
2823 /* Anything other than getting parked will be handled by other updates */
2824 if (payload->event_type != PARKED_CALL) {
2825 return;
2826 }
2827
2828 /* No one got parked? */
2829 if (!channel) {
2830 return;
2831 }
2832
2833 if (filter_channel_snapshot(channel)) {
2834 return;
2835 }
2836
2837 CDR_DEBUG("Parked Call message for channel %s: %u.%08u\n",
2838 channel->base->name,
2839 (unsigned int)stasis_message_timestamp(message)->tv_sec,
2840 (unsigned int)stasis_message_timestamp(message)->tv_usec);
2841
2843 if (!cdr) {
2844 ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
2845 ast_assert(0);
2846 return;
2847 }
2848
2849 ao2_lock(cdr);
2850
2851 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
2853 if (it_cdr->fn_table->process_parked_channel) {
2854 unhandled &= it_cdr->fn_table->process_parked_channel(it_cdr, payload);
2855 }
2856 }
2857
2858 if (unhandled) {
2859 /* Nothing handled the messgae - we need a new one! */
2860 struct cdr_object *new_cdr;
2861
2863 if (new_cdr) {
2864 /* As the new CDR is created in the single state, it is guaranteed
2865 * to have a function for the parked call message and will handle
2866 * the message */
2867 new_cdr->fn_table->process_parked_channel(new_cdr, payload);
2868 }
2869 }
2870
2871 ao2_unlock(cdr);
2872
2873 ao2_cleanup(cdr);
2874}
2875
2876/*!
2877 * \brief Handler for a synchronization message
2878 * \param data Passed on
2879 * \param sub The stasis subscription for this message callback
2880 * \param message A blank ao2 object
2881 * */
2883 struct stasis_message *message)
2884{
2885 return;
2886}
2887
2889{
2890 struct ast_cdr_config *general;
2891 struct module_config *mod_cfg;
2892
2893 mod_cfg = ao2_global_obj_ref(module_configs);
2894 if (!mod_cfg) {
2895 return NULL;
2896 }
2897 general = ao2_bump(mod_cfg->general);
2898 ao2_cleanup(mod_cfg);
2899 return general;
2900}
2901
2903{
2904 struct module_config *mod_cfg;
2905
2906 if (!config) {
2907 return;
2908 }
2909
2910 mod_cfg = ao2_global_obj_ref(module_configs);
2911 if (!mod_cfg) {
2912 return;
2913 }
2914
2915 ao2_replace(mod_cfg->general, config);
2916
2917 cdr_set_debug_mode(mod_cfg);
2919
2920 ao2_cleanup(mod_cfg);
2921}
2922
2924{
2926}
2927
2929{
2930 int success = -1;
2931 struct cdr_beitem *i = NULL;
2932
2934 AST_RWLIST_TRAVERSE(&be_list, i, list) {
2935 if (!strcasecmp(name, i->name)) {
2936 ast_debug(3, "Suspending CDR backend %s\n", i->name);
2937 i->suspended = 1;
2938 success = 0;
2939 }
2940 }
2942
2943 return success;
2944}
2945
2947{
2948 int success = -1;
2949 struct cdr_beitem *i = NULL;
2950
2952 AST_RWLIST_TRAVERSE(&be_list, i, list) {
2953 if (!strcasecmp(name, i->name)) {
2954 ast_debug(3, "Unsuspending CDR backend %s\n", i->name);
2955 i->suspended = 0;
2956 success = 0;
2957 }
2958 }
2960
2961 return success;
2962}
2963
2964static int cdr_generic_register(struct be_list *generic_list, const char *name, const char *desc, ast_cdrbe be)
2965{
2966 struct cdr_beitem *i;
2967 struct cdr_beitem *cur;
2968
2969 if (!name) {
2970 return -1;
2971 }
2972
2973 if (!be) {
2974 ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
2975
2976 return -1;
2977 }
2978
2979 i = ast_calloc(1, sizeof(*i));
2980 if (!i) {
2981 return -1;
2982 }
2983
2984 i->be = be;
2985 ast_copy_string(i->name, name, sizeof(i->name));
2986 ast_copy_string(i->desc, desc, sizeof(i->desc));
2987
2988 AST_RWLIST_WRLOCK(generic_list);
2989 AST_RWLIST_TRAVERSE(generic_list, cur, list) {
2990 if (!strcasecmp(name, cur->name)) {
2991 ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
2992 AST_RWLIST_UNLOCK(generic_list);
2993 ast_free(i);
2994
2995 return -1;
2996 }
2997 }
2998
2999 AST_RWLIST_INSERT_HEAD(generic_list, i, list);
3000 AST_RWLIST_UNLOCK(generic_list);
3001
3002 return 0;
3003}
3004
3005int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
3006{
3008}
3009
3010int ast_cdr_modifier_register(const char *name, const char *desc, ast_cdrbe be)
3011{
3012 return cdr_generic_register((struct be_list *)&mo_list, name, desc, be);
3013}
3014
3015static int ast_cdr_generic_unregister(struct be_list *generic_list, const char *name)
3016{
3017 struct cdr_beitem *match = NULL;
3018 int active_count;
3019
3020 AST_RWLIST_WRLOCK(generic_list);
3021 AST_RWLIST_TRAVERSE(generic_list, match, list) {
3022 if (!strcasecmp(name, match->name)) {
3023 break;
3024 }
3025 }
3026
3027 if (!match) {
3028 AST_RWLIST_UNLOCK(generic_list);
3029 return 0;
3030 }
3031
3033
3034 if (!match->suspended && active_count != 0) {
3035 AST_RWLIST_UNLOCK(generic_list);
3036 ast_log(AST_LOG_WARNING, "Unable to unregister CDR backend %s; %d CDRs are still active\n",
3037 name, active_count);
3038 return -1;
3039 }
3040
3041 AST_RWLIST_REMOVE(generic_list, match, list);
3042 AST_RWLIST_UNLOCK(generic_list);
3043
3044 ast_verb(5, "Unregistered '%s' CDR backend\n", name);
3045 ast_free(match);
3046
3047 return 0;
3048}
3049
3050int ast_cdr_unregister(const char *name)
3051{
3053}
3054
3056{
3057 return ast_cdr_generic_unregister((struct be_list *)&mo_list, name);
3058}
3059
3060struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr)
3061{
3062 struct ast_cdr *newcdr;
3063
3064 if (!cdr) {
3065 return NULL;
3066 }
3067 newcdr = ast_cdr_alloc();
3068 if (!newcdr) {
3069 return NULL;
3070 }
3071
3072 *newcdr = *cdr;
3074 copy_variables(&newcdr->varshead, &cdr->varshead);
3075 newcdr->next = NULL;
3076
3077 return newcdr;
3078}
3079
3080static const char *cdr_format_var_internal(struct ast_cdr *cdr, const char *name)
3081{
3082 struct ast_var_t *variables;
3083
3084 if (ast_strlen_zero(name)) {
3085 return NULL;
3086 }
3087
3088 AST_LIST_TRAVERSE(&cdr->varshead, variables, entries) {
3089 if (!strcasecmp(name, ast_var_name(variables))) {
3090 return ast_var_value(variables);
3091 }
3092 }
3093
3094 return NULL;
3095}
3096
3097static void cdr_get_tv(struct timeval when, const char *fmt, char *buf, int bufsize)
3098{
3099 if (fmt == NULL) { /* raw mode */
3100 snprintf(buf, bufsize, "%ld.%06ld", (long)when.tv_sec, (long)when.tv_usec);
3101 } else {
3102 buf[0] = '\0';/* Ensure the buffer is initialized. */
3103 if (when.tv_sec) {
3104 struct ast_tm tm;
3105
3106 ast_localtime(&when, &tm, NULL);
3107 ast_strftime(buf, bufsize, fmt, &tm);
3108 }
3109 }
3110}
3111
3112void ast_cdr_format_var(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int raw)
3113{
3114 const char *fmt = "%Y-%m-%d %T";
3115 const char *varbuf;
3116
3117 if (!cdr) {
3118 return;
3119 }
3120
3121 *ret = NULL;
3122
3123 if (!strcasecmp(name, "clid")) {
3124 ast_copy_string(workspace, cdr->clid, workspacelen);
3125 } else if (!strcasecmp(name, "src")) {
3126 ast_copy_string(workspace, cdr->src, workspacelen);
3127 } else if (!strcasecmp(name, "dst")) {
3128 ast_copy_string(workspace, cdr->dst, workspacelen);
3129 } else if (!strcasecmp(name, "dcontext")) {
3130 ast_copy_string(workspace, cdr->dcontext, workspacelen);
3131 } else if (!strcasecmp(name, "channel")) {
3132 ast_copy_string(workspace, cdr->channel, workspacelen);
3133 } else if (!strcasecmp(name, "dstchannel")) {
3134 ast_copy_string(workspace, cdr->dstchannel, workspacelen);
3135 } else if (!strcasecmp(name, "lastapp")) {
3136 ast_copy_string(workspace, cdr->lastapp, workspacelen);
3137 } else if (!strcasecmp(name, "lastdata")) {
3138 ast_copy_string(workspace, cdr->lastdata, workspacelen);
3139 } else if (!strcasecmp(name, "start")) {
3140 cdr_get_tv(cdr->start, raw ? NULL : fmt, workspace, workspacelen);
3141 } else if (!strcasecmp(name, "answer")) {
3142 cdr_get_tv(cdr->answer, raw ? NULL : fmt, workspace, workspacelen);
3143 } else if (!strcasecmp(name, "end")) {
3144 cdr_get_tv(cdr->end, raw ? NULL : fmt, workspace, workspacelen);
3145 } else if (!strcasecmp(name, "duration")) {
3146 snprintf(workspace, workspacelen, "%ld", cdr->end.tv_sec != 0 ? cdr->duration : (long)ast_tvdiff_ms(ast_tvnow(), cdr->start) / 1000);
3147 } else if (!strcasecmp(name, "billsec")) {
3148 snprintf(workspace, workspacelen, "%ld", (cdr->billsec || !ast_tvzero(cdr->end) || ast_tvzero(cdr->answer)) ? cdr->billsec : (long)ast_tvdiff_ms(ast_tvnow(), cdr->answer) / 1000);
3149 } else if (!strcasecmp(name, "disposition")) {
3150 if (raw) {
3151 snprintf(workspace, workspacelen, "%ld", cdr->disposition);
3152 } else {
3153 ast_copy_string(workspace, ast_cdr_disp2str(cdr->disposition), workspacelen);
3154 }
3155 } else if (!strcasecmp(name, "amaflags")) {
3156 if (raw) {
3157 snprintf(workspace, workspacelen, "%ld", cdr->amaflags);
3158 } else {
3159 ast_copy_string(workspace, ast_channel_amaflags2string(cdr->amaflags), workspacelen);
3160 }
3161 } else if (!strcasecmp(name, "accountcode")) {
3162 ast_copy_string(workspace, cdr->accountcode, workspacelen);
3163 } else if (!strcasecmp(name, "peeraccount")) {
3164 ast_copy_string(workspace, cdr->peeraccount, workspacelen);
3165 } else if (!strcasecmp(name, "uniqueid")) {
3166 ast_copy_string(workspace, cdr->uniqueid, workspacelen);
3167 } else if (!strcasecmp(name, "linkedid")) {
3168 ast_copy_string(workspace, cdr->linkedid, workspacelen);
3169 } else if (!strcasecmp(name, "userfield")) {
3170 ast_copy_string(workspace, cdr->userfield, workspacelen);
3171 } else if (!strcasecmp(name, "sequence")) {
3172 snprintf(workspace, workspacelen, "%d", cdr->sequence);
3173 } else if ((varbuf = cdr_format_var_internal(cdr, name))) {
3174 ast_copy_string(workspace, varbuf, workspacelen);
3175 } else {
3176 workspace[0] = '\0';
3177 }
3178
3179 if (!ast_strlen_zero(workspace)) {
3180 *ret = workspace;
3181 }
3182}
3183
3184/*!
3185 * \internal
3186 * \brief Callback that finds all CDRs that reference a particular channel by name
3187 */
3188static int cdr_object_select_all_by_name_cb(void *obj, void *arg, int flags)
3189{
3190 struct cdr_object *cdr = obj;
3191 const char *name = arg;
3192
3193 if (!strcasecmp(cdr->party_a.snapshot->base->name, name) ||
3194 (cdr->party_b.snapshot && !strcasecmp(cdr->party_b.snapshot->base->name, name))) {
3195 return CMP_MATCH;
3196 }
3197 return 0;
3198}
3199
3200/*!
3201 * \internal
3202 * \brief Callback that finds a CDR by channel name
3203 */
3204static int cdr_object_get_by_name_cb(void *obj, void *arg, int flags)
3205{
3206 struct cdr_object *cdr = obj;
3207 const char *name = arg;
3208
3209 if (!strcasecmp(cdr->party_a.snapshot->base->name, name)) {
3210 return CMP_MATCH;
3211 }
3212 return 0;
3213}
3214
3215/* Read Only CDR variables */
3216static const char * const cdr_readonly_vars[] = {
3217 "clid",
3218 "src",
3219 "dst",
3220 "dcontext",
3221 "channel",
3222 "dstchannel",
3223 "lastapp",
3224 "lastdata",
3225 "start",
3226 "answer",
3227 "end",
3228 "duration",
3229 "billsec",
3230 "disposition",
3231 "amaflags",
3232 "accountcode",
3233 "uniqueid",
3234 "linkedid",
3235 "userfield",
3236 "sequence",
3237 NULL
3238};
3239
3240int ast_cdr_setvar(const char *channel_name, const char *name, const char *value)
3241{
3242 struct cdr_object *cdr;
3243 struct cdr_object *it_cdr;
3244 struct ao2_iterator *it_cdrs;
3245 char *arg = ast_strdupa(channel_name);
3246 int x;
3247
3248 for (x = 0; cdr_readonly_vars[x]; x++) {
3249 if (!strcasecmp(name, cdr_readonly_vars[x])) {
3250 ast_log(LOG_ERROR, "Attempt to set the '%s' read-only variable!\n", name);
3251 return -1;
3252 }
3253 }
3254
3256 if (!it_cdrs) {
3257 ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
3258 return -1;
3259 }
3260
3261 for (; (cdr = ao2_iterator_next(it_cdrs)); ao2_unlock(cdr), ao2_cleanup(cdr)) {
3262 ao2_lock(cdr);
3263 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3264 struct varshead *headp = NULL;
3265
3266 if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) {
3267 continue;
3268 }
3269 if (!strcasecmp(channel_name, it_cdr->party_a.snapshot->base->name)) {
3270 headp = &it_cdr->party_a.variables;
3271 } else if (it_cdr->party_b.snapshot
3272 && !strcasecmp(channel_name, it_cdr->party_b.snapshot->base->name)) {
3273 headp = &it_cdr->party_b.variables;
3274 }
3275 if (headp) {
3276 set_variable(headp, name, value);
3277 }
3278 }
3279 }
3280 ao2_iterator_destroy(it_cdrs);
3281
3282 return 0;
3283}
3284
3285/*!
3286 * \brief Format a variable on a \ref cdr_object
3287 */
3288static void cdr_object_format_var_internal(struct cdr_object *cdr, const char *name, char *value, size_t length)
3289{
3290 struct ast_var_t *variable;
3291
3292 AST_LIST_TRAVERSE(&cdr->party_a.variables, variable, entries) {
3293 if (!strcasecmp(name, ast_var_name(variable))) {
3294 ast_copy_string(value, ast_var_value(variable), length);
3295 return;
3296 }
3297 }
3298
3299 *value = '\0';
3300}
3301
3302/*!
3303 * \brief Format one of the standard properties on a \ref cdr_object
3304 */
3305static int cdr_object_format_property(struct cdr_object *cdr_obj, const char *name, char *value, size_t length)
3306{
3307 struct ast_channel_snapshot *party_a = cdr_obj->party_a.snapshot;
3308 struct ast_channel_snapshot *party_b = cdr_obj->party_b.snapshot;
3309
3310 if (!strcasecmp(name, "clid")) {
3311 ast_callerid_merge(value, length, party_a->caller->name, party_a->caller->number, "");
3312 } else if (!strcasecmp(name, "src")) {
3313 ast_copy_string(value, party_a->caller->number, length);
3314 } else if (!strcasecmp(name, "dst")) {
3315 ast_copy_string(value, party_a->dialplan->exten, length);
3316 } else if (!strcasecmp(name, "dcontext")) {
3317 ast_copy_string(value, party_a->dialplan->context, length);
3318 } else if (!strcasecmp(name, "channel")) {
3319 ast_copy_string(value, party_a->base->name, length);
3320 } else if (!strcasecmp(name, "dstchannel")) {
3321 if (party_b) {
3322 ast_copy_string(value, party_b->base->name, length);
3323 } else {
3324 ast_copy_string(value, "", length);
3325 }
3326 } else if (!strcasecmp(name, "lastapp")) {
3327 ast_copy_string(value, party_a->dialplan->appl, length);
3328 } else if (!strcasecmp(name, "lastdata")) {
3329 ast_copy_string(value, party_a->dialplan->data, length);
3330 } else if (!strcasecmp(name, "start")) {
3331 cdr_get_tv(cdr_obj->start, NULL, value, length);
3332 } else if (!strcasecmp(name, "answer")) {
3333 cdr_get_tv(cdr_obj->answer, NULL, value, length);
3334 } else if (!strcasecmp(name, "end")) {
3335 cdr_get_tv(cdr_obj->end, NULL, value, length);
3336 } else if (!strcasecmp(name, "duration")) {
3337 snprintf(value, length, "%ld", cdr_object_get_duration(cdr_obj));
3338 } else if (!strcasecmp(name, "billsec")) {
3339 snprintf(value, length, "%ld", cdr_object_get_billsec(cdr_obj));
3340 } else if (!strcasecmp(name, "disposition")) {
3341 snprintf(value, length, "%u", cdr_obj->disposition);
3342 } else if (!strcasecmp(name, "amaflags")) {
3343 snprintf(value, length, "%d", party_a->amaflags);
3344 } else if (!strcasecmp(name, "accountcode")) {
3345 ast_copy_string(value, party_a->base->accountcode, length);
3346 } else if (!strcasecmp(name, "peeraccount")) {
3347 if (party_b) {
3348 ast_copy_string(value, party_b->base->accountcode, length);
3349 } else {
3350 ast_copy_string(value, "", length);
3351 }
3352 } else if (!strcasecmp(name, "uniqueid")) {
3353 ast_copy_string(value, party_a->base->uniqueid, length);
3354 } else if (!strcasecmp(name, "linkedid")) {
3355 ast_copy_string(value, cdr_obj->linkedid, length);
3356 } else if (!strcasecmp(name, "userfield")) {
3357 ast_copy_string(value, cdr_obj->party_a.userfield, length);
3358 } else if (!strcasecmp(name, "sequence")) {
3359 snprintf(value, length, "%u", cdr_obj->sequence);
3360 } else {
3361 return 1;
3362 }
3363
3364 return 0;
3365}
3366
3367/*! \internal
3368 * \brief Look up and retrieve a CDR object by channel name
3369 * \param name The name of the channel
3370 * \retval NULL on error
3371 * \return The \ref cdr_object for the channel on success, with the reference
3372 * count bumped by one.
3373 */
3374static struct cdr_object *cdr_object_get_by_name(const char *name)
3375{
3376 char *param;
3377
3378 if (ast_strlen_zero(name)) {
3379 return NULL;
3380 }
3381
3382 param = ast_strdupa(name);
3384}
3385
3386int ast_cdr_getvar(const char *channel_name, const char *name, char *value, size_t length)
3387{
3388 struct cdr_object *cdr;
3389 struct cdr_object *cdr_obj;
3390
3391 if (ast_strlen_zero(name)) {
3392 return 1;
3393 }
3394
3395 cdr = cdr_object_get_by_name(channel_name);
3396 if (!cdr) {
3397 ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
3398 return 1;
3399 }
3400
3401 ao2_lock(cdr);
3402
3403 cdr_obj = cdr->last;
3404 if (cdr_object_format_property(cdr_obj, name, value, length)) {
3405 /* Property failed; attempt variable */
3406 cdr_object_format_var_internal(cdr_obj, name, value, length);
3407 }
3408
3409 ao2_unlock(cdr);
3410
3411 ao2_cleanup(cdr);
3412 return 0;
3413}
3414
3415int ast_cdr_serialize_variables(const char *channel_name, struct ast_str **buf, char delim, char sep)
3416{
3417 struct cdr_object *cdr;
3418 struct cdr_object *it_cdr;
3419 struct ast_var_t *variable;
3420 const char *var;
3421 char workspace[256];
3422 int total = 0, x = 0, i;
3423
3424 cdr = cdr_object_get_by_name(channel_name);
3425 if (!cdr) {
3427 ast_log(AST_LOG_ERROR, "Unable to find CDR for channel %s\n", channel_name);
3428 }
3429 return 0;
3430 }
3431
3433
3434 ao2_lock(cdr);
3435 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3436 if (++x > 1) {
3437 ast_str_append(buf, 0, "\n");
3438 }
3439
3440 AST_LIST_TRAVERSE(&it_cdr->party_a.variables, variable, entries) {
3441 if (!(var = ast_var_name(variable))) {
3442 continue;
3443 }
3444
3445 if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, var, delim, S_OR(ast_var_value(variable), ""), sep) < 0) {
3446 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
3447 break;
3448 }
3449
3450 total++;
3451 }
3452
3453 for (i = 0; cdr_readonly_vars[i]; i++) {
3454 if (cdr_object_format_property(it_cdr, cdr_readonly_vars[i], workspace, sizeof(workspace))) {
3455 /* Unhandled read-only CDR variable. */
3456 ast_assert(0);
3457 continue;
3458 }
3459
3460 if (!ast_strlen_zero(workspace)
3461 && ast_str_append(buf, 0, "level %d: %s%c%s%c", x, cdr_readonly_vars[i], delim, workspace, sep) < 0) {
3462 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
3463 break;
3464 }
3465 total++;
3466 }
3467 }
3468 ao2_unlock(cdr);
3469 ao2_cleanup(cdr);
3470 return total;
3471}
3472
3473void ast_cdr_free(struct ast_cdr *cdr)
3474{
3475 while (cdr) {
3476 struct ast_cdr *next = cdr->next;
3477
3478 free_variables(&cdr->varshead);
3479 ast_free(cdr);
3480 cdr = next;
3481 }
3482}
3483
3485{
3486 struct ast_cdr *x;
3487
3488 x = ast_calloc(1, sizeof(*x));
3489 return x;
3490}
3491
3493{
3494 switch (disposition) {
3495 case AST_CDR_NULL:
3496 return "NO ANSWER"; /* by default, for backward compatibility */
3497 case AST_CDR_NOANSWER:
3498 return "NO ANSWER";
3499 case AST_CDR_FAILED:
3500 return "FAILED";
3501 case AST_CDR_BUSY:
3502 return "BUSY";
3503 case AST_CDR_ANSWERED:
3504 return "ANSWERED";
3505 case AST_CDR_CONGESTION:
3506 return "CONGESTION";
3507 }
3508 return "UNKNOWN";
3509}
3510
3512 const char *channel_name;
3513 const char *userfield;
3514};
3515
3516/*! \brief Callback used to update the userfield on Party B on all CDRs */
3517static int cdr_object_update_party_b_userfield_cb(void *obj, void *arg, void *data, int flags)
3518{
3519 struct cdr_object *cdr = obj;
3520
3521 if ((cdr->fn_table != &finalized_state_fn_table || !cdr->next)
3522 && !strcasecmp(cdr->party_b_name, arg)) {
3523 struct party_b_userfield_update *info = data;
3524
3525 /*
3526 * For sanity's sake we also assert the party_b snapshot
3527 * is consistent with the key.
3528 */
3530 && !strcasecmp(cdr->party_b.snapshot->base->name, info->channel_name));
3531
3532 ast_copy_string(cdr->party_b.userfield, info->userfield,
3533 sizeof(cdr->party_b.userfield));
3534 }
3535
3536 return 0;
3537}
3538
3539void ast_cdr_setuserfield(const char *channel_name, const char *userfield)
3540{
3541 struct cdr_object *cdr;
3542 struct party_b_userfield_update party_b_info = {
3544 .userfield = userfield,
3545 };
3546 struct cdr_object *it_cdr;
3547
3548 /* Handle Party A */
3549 cdr = cdr_object_get_by_name(channel_name);
3550 if (cdr) {
3551 ao2_lock(cdr);
3552 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3553 if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) {
3554 continue;
3555 }
3556 ast_copy_string(it_cdr->party_a.userfield, userfield,
3557 sizeof(it_cdr->party_a.userfield));
3558 }
3559 ao2_unlock(cdr);
3560 }
3561
3562 /* Handle Party B */
3565 &party_b_info);
3566
3567 ao2_cleanup(cdr);
3568}
3569
3570static void post_cdr(struct ast_cdr *cdr)
3571{
3572 struct module_config *mod_cfg;
3573 struct cdr_beitem *i;
3574
3575 mod_cfg = ao2_global_obj_ref(module_configs);
3576 if (!mod_cfg) {
3577 return;
3578 }
3579
3580 for (; cdr ; cdr = cdr->next) {
3581 /* For people, who don't want to see unanswered single-channel events */
3582 if (!ast_test_flag(&mod_cfg->general->settings, CDR_UNANSWERED) &&
3585 ast_debug(1, "Skipping CDR for %s since we weren't answered\n", cdr->channel);
3586 continue;
3587 }
3588
3589 /* Modify CDR's */
3591 AST_RWLIST_TRAVERSE(&mo_list, i, list) {
3592 i->be(cdr);
3593 }
3595
3597 continue;
3598 }
3600 AST_RWLIST_TRAVERSE(&be_list, i, list) {
3601 if (!i->suspended) {
3602 i->be(cdr);
3603 }
3604 }
3606 }
3607 ao2_cleanup(mod_cfg);
3608}
3609
3610int ast_cdr_set_property(const char *channel_name, enum ast_cdr_options option)
3611{
3612 struct cdr_object *cdr;
3613 struct cdr_object *it_cdr;
3614
3615 cdr = cdr_object_get_by_name(channel_name);
3616 if (!cdr) {
3617 return -1;
3618 }
3619
3620 ao2_lock(cdr);
3621 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3622 if (it_cdr->fn_table == &finalized_state_fn_table) {
3623 continue;
3624 }
3625 /* Note: in general, set the flags on both the CDR record as well as the
3626 * Party A. Sometimes all we have is the Party A to look at.
3627 */
3628 ast_set_flag(&it_cdr->flags, option);
3629 ast_set_flag(&it_cdr->party_a, option);
3630 }
3631 ao2_unlock(cdr);
3632
3633 ao2_cleanup(cdr);
3634 return 0;
3635}
3636
3637int ast_cdr_clear_property(const char *channel_name, enum ast_cdr_options option)
3638{
3639 struct cdr_object *cdr;
3640 struct cdr_object *it_cdr;
3641
3642 cdr = cdr_object_get_by_name(channel_name);
3643 if (!cdr) {
3644 return -1;
3645 }
3646
3647 ao2_lock(cdr);
3648 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3649 if (it_cdr->fn_table == &finalized_state_fn_table) {
3650 continue;
3651 }
3652 ast_clear_flag(&it_cdr->flags, option);
3653 }
3654 ao2_unlock(cdr);
3655
3656 ao2_cleanup(cdr);
3657 return 0;
3658}
3659
3660int ast_cdr_reset(const char *channel_name, int keep_variables)
3661{
3662 struct cdr_object *cdr;
3663 struct ast_var_t *vardata;
3664 struct cdr_object *it_cdr;
3665
3666 cdr = cdr_object_get_by_name(channel_name);
3667 if (!cdr) {
3668 return -1;
3669 }
3670
3671 ao2_lock(cdr);
3672 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
3673 /* clear variables */
3674 if (!keep_variables) {
3675 while ((vardata = AST_LIST_REMOVE_HEAD(&it_cdr->party_a.variables, entries))) {
3676 ast_var_delete(vardata);
3677 }
3678 if (cdr->party_b.snapshot) {
3679 while ((vardata = AST_LIST_REMOVE_HEAD(&it_cdr->party_b.variables, entries))) {
3680 ast_var_delete(vardata);
3681 }
3682 }
3683 }
3684
3685 /* Reset to initial state */
3686 memset(&it_cdr->start, 0, sizeof(it_cdr->start));
3687 memset(&it_cdr->end, 0, sizeof(it_cdr->end));
3688 memset(&it_cdr->answer, 0, sizeof(it_cdr->answer));
3689 it_cdr->start = ast_tvnow();
3690 it_cdr->lastevent = it_cdr->start;
3692 }
3693 ao2_unlock(cdr);
3694
3695 ao2_cleanup(cdr);
3696 return 0;
3697}
3698
3699int ast_cdr_fork(const char *channel_name, struct ast_flags *options)
3700{
3701 RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
3702 struct cdr_object *new_cdr;
3703 struct cdr_object *it_cdr;
3704 struct cdr_object *cdr_obj;
3705
3706 if (!cdr) {
3707 return -1;
3708 }
3709
3710 {
3711 SCOPED_AO2LOCK(lock, cdr);
3712 struct timeval now = ast_tvnow();
3713
3714 cdr_obj = cdr->last;
3715 if (cdr_obj->fn_table == &finalized_state_fn_table) {
3716 /* If the last CDR in the chain is finalized, don't allow a fork -
3717 * things are already dying at this point
3718 */
3719 return -1;
3720 }
3721
3722 /* Copy over the basic CDR information. The Party A information is
3723 * copied over automatically as part of the append
3724 */
3725 ast_debug(1, "Forking CDR for channel %s\n", cdr->party_a.snapshot->base->name);
3726 new_cdr = cdr_object_create_and_append(cdr, &now);
3727 if (!new_cdr) {
3728 return -1;
3729 }
3730 new_cdr->fn_table = cdr_obj->fn_table;
3731 ast_string_field_set(new_cdr, bridge, cdr->bridge);
3732 ast_string_field_set(new_cdr, appl, cdr->appl);
3733 ast_string_field_set(new_cdr, data, cdr->data);
3734 ast_string_field_set(new_cdr, context, cdr->context);
3735 ast_string_field_set(new_cdr, exten, cdr->exten);
3736 new_cdr->flags = cdr->flags;
3737 /* Explicitly clear the AST_CDR_LOCK_APP flag - we want
3738 * the application to be changed on the new CDR if the
3739 * dialplan demands it
3740 */
3742
3743 /* If there's a Party B, copy it over as well */
3744 if (cdr_obj->party_b.snapshot) {
3745 new_cdr->party_b.snapshot = cdr_obj->party_b.snapshot;
3746 ao2_ref(new_cdr->party_b.snapshot, +1);
3747 cdr_all_relink(new_cdr);
3748 strcpy(new_cdr->party_b.userfield, cdr_obj->party_b.userfield);
3749 new_cdr->party_b.flags = cdr_obj->party_b.flags;
3751 copy_variables(&new_cdr->party_b.variables, &cdr_obj->party_b.variables);
3752 }
3753 }
3754 new_cdr->start = cdr_obj->start;
3755 new_cdr->answer = cdr_obj->answer;
3756 new_cdr->lastevent = ast_tvnow();
3757
3758 /* Modify the times based on the flags passed in */
3760 && new_cdr->party_a.snapshot->state == AST_STATE_UP) {
3761 new_cdr->answer = ast_tvnow();
3762 }
3764 new_cdr->answer = ast_tvnow();
3765 new_cdr->start = ast_tvnow();
3766 }
3767
3768 /* Create and append, by default, copies over the variables */
3770 free_variables(&new_cdr->party_a.variables);
3771 }
3772
3773 /* Finalize any current CDRs */
3775 for (it_cdr = cdr; it_cdr != new_cdr; it_cdr = it_cdr->next) {
3776 if (it_cdr->fn_table == &finalized_state_fn_table) {
3777 continue;
3778 }
3779 /* Force finalization on the CDR. This will bypass any checks for
3780 * end before 'h' extension.
3781 */
3782 cdr_object_finalize(it_cdr);
3784 }
3785 }
3786 }
3787
3788 return 0;
3789}
3790
3791/*! \note Don't call without cdr_batch_lock */
3792static void reset_batch(void)
3793{
3794 batch->size = 0;
3795 batch->head = NULL;
3796 batch->tail = NULL;
3797}
3798
3799/*! \note Don't call without cdr_batch_lock */
3800static int init_batch(void)
3801{
3802 /* This is the single meta-batch used to keep track of all CDRs during the entire life of the program */
3803 if (!(batch = ast_malloc(sizeof(*batch))))
3804 return -1;
3805
3806 reset_batch();
3807
3808 return 0;
3809}
3810
3811static void *do_batch_backend_process(void *data)
3812{
3813 struct cdr_batch_item *processeditem;
3814 struct cdr_batch_item *batchitem = data;
3815
3816 /* Push each CDR into storage mechanism(s) and free all the memory */
3817 while (batchitem) {
3818 post_cdr(batchitem->cdr);
3819 ast_cdr_free(batchitem->cdr);
3820 processeditem = batchitem;
3821 batchitem = batchitem->next;
3822 ast_free(processeditem);
3823 }
3824
3825 return NULL;
3826}
3827
3828static void cdr_submit_batch(int do_shutdown)
3829{
3830 struct module_config *mod_cfg;
3831 struct cdr_batch_item *oldbatchitems = NULL;
3832 pthread_t batch_post_thread = AST_PTHREADT_NULL;
3833
3834 /* if there's no batch, or no CDRs in the batch, then there's nothing to do */
3835 if (!batch || !batch->head) {
3836 return;
3837 }
3838
3839 /* move the old CDRs aside, and prepare a new CDR batch */
3841 oldbatchitems = batch->head;
3842 reset_batch();
3844
3845 mod_cfg = ao2_global_obj_ref(module_configs);
3846
3847 /* if configured, spawn a new thread to post these CDRs,
3848 also try to save as much as possible if we are shutting down safely */
3849 if (!mod_cfg
3851 || do_shutdown) {
3852 ast_debug(1, "CDR single-threaded batch processing begins now\n");
3853 do_batch_backend_process(oldbatchitems);
3854 } else {
3855 if (ast_pthread_create_detached_background(&batch_post_thread, NULL, do_batch_backend_process, oldbatchitems)) {
3856 ast_log(LOG_WARNING, "CDR processing thread could not detach, now trying in this thread\n");
3857 do_batch_backend_process(oldbatchitems);
3858 } else {
3859 ast_debug(1, "CDR multi-threaded batch processing begins now\n");
3860 }
3861 }
3862
3863 ao2_cleanup(mod_cfg);
3864}
3865
3866static int submit_scheduled_batch(const void *data)
3867{
3868 struct module_config *mod_cfg;
3869 int nextms;
3870
3872
3873 mod_cfg = ao2_global_obj_ref(module_configs);
3874 if (!mod_cfg) {
3875 return 0;
3876 }
3877
3878 /* Calculate the next scheduled interval */
3879 nextms = mod_cfg->general->batch_settings.time * 1000;
3880
3881 ao2_cleanup(mod_cfg);
3882
3883 return nextms;
3884}
3885
3886/*! Do not hold the batch lock while calling this function */
3887static void start_batch_mode(void)
3888{
3889 /* Prevent two deletes from happening at the same time */
3891 /* this is okay since we are not being called from within the scheduler */
3893 /* schedule the submission to occur ASAP (1 ms) */
3896
3897 /* signal the do_cdr thread to wakeup early and do some work (that lazy thread ;) */
3901}
3902
3903static void cdr_detach(struct ast_cdr *cdr)
3904{
3905 struct cdr_batch_item *newtail;
3906 int curr;
3907 RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
3908 int submit_batch = 0;
3909
3910 if (!cdr) {
3911 return;
3912 }
3913
3914 /* maybe they disabled CDR stuff completely, so just drop it */
3915 if (!mod_cfg || !ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
3916 ast_debug(1, "Dropping CDR !\n");
3918 return;
3919 }
3920
3921 /* post stuff immediately if we are not in batch mode, this is legacy behaviour */
3922 if (!ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
3923 post_cdr(cdr);
3925 return;
3926 }
3927
3928 /* otherwise, each CDR gets put into a batch list (at the end) */
3929 ast_debug(1, "CDR detaching from this thread\n");
3930
3931 /* we'll need a new tail for every CDR */
3932 if (!(newtail = ast_calloc(1, sizeof(*newtail)))) {
3933 post_cdr(cdr);
3935 return;
3936 }
3937
3938 /* don't traverse a whole list (just keep track of the tail) */
3940 if (!batch)
3941 init_batch();
3942 if (!batch->head) {
3943 /* new batch is empty, so point the head at the new tail */
3944 batch->head = newtail;
3945 } else {
3946 /* already got a batch with something in it, so just append a new tail */
3947 batch->tail->next = newtail;
3948 }
3949 newtail->cdr = cdr;
3950 batch->tail = newtail;
3951 curr = batch->size++;
3952
3953 /* if we have enough stuff to post, then do it */
3954 if (curr >= (mod_cfg->general->batch_settings.size - 1)) {
3955 submit_batch = 1;
3956 }
3958
3959 /* Don't submit a batch with cdr_batch_lock held */
3960 if (submit_batch) {
3962 }
3963}
3964
3965static void *do_cdr(void *data)
3966{
3967 struct timespec timeout;
3968 int schedms;
3969 int numevents = 0;
3970
3971 for (;;) {
3972 struct timeval now;
3973 schedms = ast_sched_wait(sched);
3974 /* this shouldn't happen, but provide a 1 second default just in case */
3975 if (schedms < 0)
3976 schedms = 1000;
3977 now = ast_tvadd(ast_tvnow(), ast_samp2tv(schedms, 1000));
3978 timeout.tv_sec = now.tv_sec;
3979 timeout.tv_nsec = now.tv_usec * 1000;
3980 /* prevent stuff from clobbering cdr_pending_cond, then wait on signals sent to it until the timeout expires */
3983 numevents = ast_sched_runq(sched);
3985 ast_debug(2, "Processed %d CDR batches from the run queue\n", numevents);
3986 }
3987
3988 return NULL;
3989}
3990
3991static char *handle_cli_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3992{
3993 struct module_config *mod_cfg;
3994
3995 switch (cmd) {
3996 case CLI_INIT:
3997 e->command = "cdr set debug [on|off]";
3998 e->usage = "Enable or disable extra debugging in the CDR Engine. Note\n"
3999 "that this will dump debug information to the VERBOSE setting\n"
4000 "and should only be used when debugging information from the\n"
4001 "CDR engine is needed.\n";
4002 return NULL;
4003 case CLI_GENERATE:
4004 return NULL;
4005 }
4006
4007 if (a->argc != 4) {
4008 return CLI_SHOWUSAGE;
4009 }
4010
4011 mod_cfg = ao2_global_obj_ref(module_configs);
4012 if (!mod_cfg) {
4013 ast_cli(a->fd, "Could not set CDR debugging mode\n");
4014 return CLI_SUCCESS;
4015 }
4016 if (!strcasecmp(a->argv[3], "on")
4017 && !ast_test_flag(&mod_cfg->general->settings, CDR_DEBUG)) {
4019 ast_cli(a->fd, "CDR debugging enabled\n");
4020 } else if (!strcasecmp(a->argv[3], "off")
4021 && ast_test_flag(&mod_cfg->general->settings, CDR_DEBUG)) {
4023 ast_cli(a->fd, "CDR debugging disabled\n");
4024 }
4025 cdr_set_debug_mode(mod_cfg);
4026 ao2_cleanup(mod_cfg);
4027
4028 return CLI_SUCCESS;
4029}
4030
4031/*! \brief Complete user input for 'cdr show' */
4032static char *cli_complete_show(struct ast_cli_args *a)
4033{
4034 int wordlen = strlen(a->word);
4035 struct ao2_iterator it_cdrs;
4036 struct cdr_object *cdr;
4037
4039 while ((cdr = ao2_iterator_next(&it_cdrs))) {
4040 if (!strncasecmp(a->word, cdr->party_a.snapshot->base->name, wordlen)) {
4042 ao2_ref(cdr, -1);
4043 break;
4044 }
4045 }
4046 ao2_ref(cdr, -1);
4047 }
4048 ao2_iterator_destroy(&it_cdrs);
4049
4050 return NULL;
4051}
4052
4054{
4055 struct ao2_iterator it_cdrs;
4056 struct cdr_object *cdr;
4057 char start_time_buffer[64];
4058 char answer_time_buffer[64];
4059 char end_time_buffer[64];
4060
4061#define TITLE_STRING "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
4062#define FORMAT_STRING "%-25.25s %-25.25s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
4063
4064 ast_cli(a->fd, "\n");
4065 ast_cli(a->fd, "Channels with Call Detail Record (CDR) Information\n");
4066 ast_cli(a->fd, "--------------------------------------------------\n");
4067 ast_cli(a->fd, TITLE_STRING, "Channel", "Dst. Channel", "LastApp", "Start", "Answer", "End", "Billsec", "Duration");
4068
4070 for (; (cdr = ao2_iterator_next(&it_cdrs)); ao2_cleanup(cdr)) {
4071 struct cdr_object *it_cdr;
4072 struct timeval start_time = { 0, };
4073 struct timeval answer_time = { 0, };
4074 struct timeval end_time = { 0, };
4075
4076 SCOPED_AO2LOCK(lock, cdr);
4077
4078 /* Calculate the start, end, answer, billsec, and duration over the
4079 * life of all of the CDR entries
4080 */
4081 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4082 if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
4083 continue;
4084 }
4085 if (ast_tvzero(start_time)) {
4086 start_time = it_cdr->start;
4087 }
4088 if (!ast_tvzero(it_cdr->answer) && ast_tvzero(answer_time)) {
4089 answer_time = it_cdr->answer;
4090 }
4091 }
4092
4093 /* If there was no start time, then all CDRs were for a dialed channel; skip */
4094 if (ast_tvzero(start_time)) {
4095 continue;
4096 }
4097 it_cdr = cdr->last;
4098
4099 end_time = ast_tvzero(it_cdr->end) ? ast_tvnow() : it_cdr->end;
4100 cdr_get_tv(start_time, "%T", start_time_buffer, sizeof(start_time_buffer));
4101 cdr_get_tv(answer_time, "%T", answer_time_buffer, sizeof(answer_time_buffer));
4102 cdr_get_tv(end_time, "%T", end_time_buffer, sizeof(end_time_buffer));
4104 it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<none>",
4105 it_cdr->appl,
4106 start_time_buffer,
4107 answer_time_buffer,
4108 end_time_buffer,
4109 ast_tvzero(answer_time) ? 0 : (long)ast_tvdiff_ms(end_time, answer_time) / 1000,
4110 (long)ast_tvdiff_ms(end_time, start_time) / 1000);
4111 }
4112 ao2_iterator_destroy(&it_cdrs);
4113#undef FORMAT_STRING
4114#undef TITLE_STRING
4115}
4116
4117static void cli_show_channel(struct ast_cli_args *a)
4118{
4119 struct cdr_object *it_cdr;
4120 char clid[64];
4121 char start_time_buffer[64];
4122 char answer_time_buffer[64];
4123 char end_time_buffer[64];
4124 const char *channel_name = a->argv[3];
4125 struct cdr_object *cdr;
4126
4127#define TITLE_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n"
4128#define FORMAT_STRING "%-10.10s %-20.20s %-25.25s %-15.15s %-15.15s %-8.8s %-8.8s %-8.8s %-8.8ld %-8.8ld\n"
4129
4130 cdr = cdr_object_get_by_name(channel_name);
4131 if (!cdr) {
4132 ast_cli(a->fd, "Unknown channel: %s\n", channel_name);
4133 return;
4134 }
4135
4136 ast_cli(a->fd, "\n");
4137 ast_cli(a->fd, "Call Detail Record (CDR) Information for %s\n", channel_name);
4138 ast_cli(a->fd, "--------------------------------------------------\n");
4139 ast_cli(a->fd, TITLE_STRING, "AccountCode", "CallerID", "Dst. Channel", "LastApp", "Data", "Start", "Answer", "End", "Billsec", "Duration");
4140
4141 ao2_lock(cdr);
4142 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4143 struct timeval end;
4144
4145 if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
4146 continue;
4147 }
4148 ast_callerid_merge(clid, sizeof(clid), it_cdr->party_a.snapshot->caller->name, it_cdr->party_a.snapshot->caller->number, "");
4149 if (ast_tvzero(it_cdr->end)) {
4150 end = ast_tvnow();
4151 } else {
4152 end = it_cdr->end;
4153 }
4154 cdr_get_tv(it_cdr->start, "%T", start_time_buffer, sizeof(start_time_buffer));
4155 cdr_get_tv(it_cdr->answer, "%T", answer_time_buffer, sizeof(answer_time_buffer));
4156 cdr_get_tv(end, "%T", end_time_buffer, sizeof(end_time_buffer));
4157 ast_cli(a->fd, FORMAT_STRING,
4158 it_cdr->party_a.snapshot->base->accountcode,
4159 clid,
4160 it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<none>",
4161 it_cdr->appl,
4162 it_cdr->data,
4163 start_time_buffer,
4164 answer_time_buffer,
4165 end_time_buffer,
4166 (long)ast_tvdiff_ms(end, it_cdr->answer) / 1000,
4167 (long)ast_tvdiff_ms(end, it_cdr->start) / 1000);
4168 }
4169 ao2_unlock(cdr);
4170
4171 ao2_cleanup(cdr);
4172
4173#undef FORMAT_STRING
4174#undef TITLE_STRING
4175}
4176
4177static char *handle_cli_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4178{
4179 switch (cmd) {
4180 case CLI_INIT:
4181 e->command = "cdr show active";
4182 e->usage =
4183 "Usage: cdr show active [channel]\n"
4184 " Displays a summary of all Call Detail Records when [channel]\n"
4185 " is omitted; displays all of the Call Detail Records\n"
4186 " currently in flight for a given [channel] when [channel] is\n"
4187 " specified.\n\n"
4188 " Note that this will not display Call Detail Records that\n"
4189 " have already been dispatched to a backend storage, nor for\n"
4190 " channels that are no longer active.\n";
4191 return NULL;
4192 case CLI_GENERATE:
4193 return cli_complete_show(a);
4194 }
4195
4196 if (a->argc > 4) {
4197 return CLI_SHOWUSAGE;
4198 } else if (a->argc < 4) {
4200 } else {
4202 }
4203
4204 return CLI_SUCCESS;
4205}
4206
4207static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4208{
4209 struct cdr_beitem *beitem = NULL;
4210 struct module_config *mod_cfg;
4211 int cnt = 0;
4212 long nextbatchtime = 0;
4213
4214 switch (cmd) {
4215 case CLI_INIT:
4216 e->command = "cdr show status";
4217 e->usage =
4218 "Usage: cdr show status\n"
4219 " Displays the Call Detail Record engine system status.\n";
4220 return NULL;
4221 case CLI_GENERATE:
4222 return NULL;
4223 }
4224
4225 if (a->argc > 3) {
4226 return CLI_SHOWUSAGE;
4227 }
4228
4229 mod_cfg = ao2_global_obj_ref(module_configs);
4230 if (!mod_cfg) {
4231 return CLI_FAILURE;
4232 }
4233
4234 ast_cli(a->fd, "\n");
4235 ast_cli(a->fd, "Call Detail Record (CDR) settings\n");
4236 ast_cli(a->fd, "----------------------------------\n");
4237 ast_cli(a->fd, " Logging: %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED) ? "Enabled" : "Disabled");
4238 ast_cli(a->fd, " Mode: %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE) ? "Batch" : "Simple");
4239 if (ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
4240 ast_cli(a->fd, " Log calls by default: %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_CHANNEL_DEFAULT_ENABLED) ? "Yes" : "No");
4241 ast_cli(a->fd, " Log unanswered calls: %s\n", ast_test_flag(&mod_cfg->general->settings, CDR_UNANSWERED) ? "Yes" : "No");
4242 ast_cli(a->fd, " Log congestion: %s\n\n", ast_test_flag(&mod_cfg->general->settings, CDR_CONGESTION) ? "Yes" : "No");
4243 ast_cli(a->fd, " Ignore bridging changes: %s\n\n", ast_test_flag(&mod_cfg->general->settings, CDR_IGNORE_STATE_CHANGES) ? "Yes" : "No");
4244 ast_cli(a->fd, " Ignore dial state changes: %s\n\n", ast_test_flag(&mod_cfg->general->settings, CDR_IGNORE_DIAL_CHANGES) ? "Yes" : "No");
4245 if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4246 ast_cli(a->fd, "* Batch Mode Settings\n");
4247 ast_cli(a->fd, " -------------------\n");
4248 if (batch)
4249 cnt = batch->size;
4250 if (cdr_sched > -1)
4251 nextbatchtime = ast_sched_when(sched, cdr_sched);
4252 ast_cli(a->fd, " Safe shutdown: %s\n", ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SAFE_SHUTDOWN) ? "Enabled" : "Disabled");
4253 ast_cli(a->fd, " Threading model: %s\n", ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SCHEDULER_ONLY) ? "Scheduler only" : "Scheduler plus separate threads");
4254 ast_cli(a->fd, " Current batch size: %d record%s\n", cnt, ESS(cnt));
4255 ast_cli(a->fd, " Maximum batch size: %u record%s\n", mod_cfg->general->batch_settings.size, ESS(mod_cfg->general->batch_settings.size));
4256 ast_cli(a->fd, " Maximum batch time: %u second%s\n", mod_cfg->general->batch_settings.time, ESS(mod_cfg->general->batch_settings.time));
4257 ast_cli(a->fd, " Next batch processing time: %ld second%s\n\n", nextbatchtime, ESS(nextbatchtime));
4258 }
4259 ast_cli(a->fd, "* Registered Backends\n");
4260 ast_cli(a->fd, " -------------------\n");
4262 if (AST_RWLIST_EMPTY(&be_list)) {
4263 ast_cli(a->fd, " (none)\n");
4264 } else {
4265 AST_RWLIST_TRAVERSE(&be_list, beitem, list) {
4266 ast_cli(a->fd, " %s%s\n", beitem->name, beitem->suspended ? " (suspended) " : "");
4267 }
4268 }
4270 ast_cli(a->fd, "\n");
4271 }
4272
4273 ao2_cleanup(mod_cfg);
4274 return CLI_SUCCESS;
4275}
4276
4277static char *handle_cli_submit(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4278{
4279 struct module_config *mod_cfg;
4280
4281 switch (cmd) {
4282 case CLI_INIT:
4283 e->command = "cdr submit";
4284 e->usage =
4285 "Usage: cdr submit\n"
4286 "Posts all pending batched CDR data to the configured CDR\n"
4287 "backend engine modules.\n";
4288 return NULL;
4289 case CLI_GENERATE:
4290 return NULL;
4291 }
4292 if (a->argc > 2) {
4293 return CLI_SHOWUSAGE;
4294 }
4295
4296 mod_cfg = ao2_global_obj_ref(module_configs);
4297 if (!mod_cfg) {
4298 return CLI_FAILURE;
4299 }
4300
4301 if (!ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
4302 ast_cli(a->fd, "Cannot submit CDR batch: CDR engine disabled.\n");
4303 } else if (!ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4304 ast_cli(a->fd, "Cannot submit CDR batch: batch mode not enabled.\n");
4305 } else {
4307 ast_cli(a->fd, "Submitted CDRs to backend engines for processing. This may take a while.\n");
4308 }
4309 ao2_cleanup(mod_cfg);
4310
4311 return CLI_SUCCESS;
4312}
4313
4314static struct ast_cli_entry cli_commands[] = {
4315 AST_CLI_DEFINE(handle_cli_submit, "Posts all pending batched CDR data"),
4316 AST_CLI_DEFINE(handle_cli_status, "Display the CDR status"),
4317 AST_CLI_DEFINE(handle_cli_show, "Display active CDRs for channels"),
4318 AST_CLI_DEFINE(handle_cli_debug, "Enable debugging in the CDR engine"),
4319};
4320
4321/*!
4322 * \brief This dispatches *all* \ref cdr_object. It should only be used during
4323 * shutdown, so that we get billing records for everything that we can.
4324 */
4325static int cdr_object_dispatch_all_cb(void *obj, void *arg, int flags)
4326{
4327 struct cdr_object *cdr = obj;
4328 struct cdr_object *it_cdr;
4329
4330 ao2_lock(cdr);
4331 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4333 }
4335 ao2_unlock(cdr);
4336
4337 cdr_all_unlink(cdr);
4338
4339 return CMP_MATCH;
4340}
4341
4342static void finalize_batch_mode(void)
4343{
4345 return;
4346 }
4347 /* wake up the thread so it will exit */
4348 pthread_cancel(cdr_thread);
4349 pthread_kill(cdr_thread, SIGURG);
4350 pthread_join(cdr_thread, NULL);
4354}
4355
4357{
4358 if (!stasis_router) {
4359 return NULL;
4360 }
4361
4363 return stasis_router;
4364}
4365
4366/*!
4367 * \brief Destroy the active Stasis subscriptions
4368 */
4369static void destroy_subscriptions(void)
4370{
4374}
4375
4376/*!
4377 * \brief Create the Stasis subcriptions for CDRs
4378 */
4379static int create_subscriptions(void)
4380{
4381 if (!cdr_topic) {
4382 return -1;
4383 }
4384
4386 return 0;
4387 }
4388
4390 if (!channel_subscription) {
4391 return -1;
4392 }
4394 if (!bridge_subscription) {
4395 return -1;
4396 }
4398 if (!parking_subscription) {
4399 return -1;
4400 }
4401
4402 return 0;
4403}
4404
4405static int process_config(int reload)
4406{
4407 if (!reload) {
4408 if (aco_info_init(&cfg_info)) {
4409 return 1;
4410 }
4411
4426 }
4427
4428 if (aco_process_config(&cfg_info, reload) == ACO_PROCESS_ERROR) {
4429 struct module_config *mod_cfg;
4430
4431 if (reload) {
4432 return 1;
4433 }
4434
4435 /* If we couldn't process the configuration and this wasn't a reload,
4436 * create a default config
4437 */
4438 mod_cfg = module_config_alloc();
4439 if (!mod_cfg
4440 || aco_set_defaults(&general_option, "general", mod_cfg->general)) {
4441 ao2_cleanup(mod_cfg);
4442 return 1;
4443 }
4444 ast_log(LOG_NOTICE, "Failed to process CDR configuration; using defaults\n");
4445 ao2_global_obj_replace_unref(module_configs, mod_cfg);
4446 cdr_set_debug_mode(mod_cfg);
4447 ao2_cleanup(mod_cfg);
4448 }
4449
4450 return 0;
4451}
4452
4453static void cdr_engine_shutdown(void)
4454{
4457
4459 cdr_topic = NULL;
4460
4461 STASIS_MESSAGE_TYPE_CLEANUP(cdr_sync_message_type);
4462
4468 sched = NULL;
4469 ast_free(batch);
4470 batch = NULL;
4471
4472 aco_info_destroy(&cfg_info);
4473 ao2_global_obj_release(module_configs);
4474
4475 ao2_container_unregister("cdrs_master");
4478
4479 ao2_container_unregister("cdrs_all");
4482}
4483
4485{
4486 /* Only create the thread level portions once */
4490 ast_log(LOG_ERROR, "Unable to start CDR thread.\n");
4491 return;
4492 }
4493 }
4494
4495 /* Start the batching process */
4497
4498 ast_log(LOG_NOTICE, "CDR batch mode logging enabled, first of either size %u or time %u seconds.\n",
4499 config->batch_settings.size, config->batch_settings.time);
4500}
4501
4502/*!
4503 * \internal
4504 * \brief Print master CDR container object.
4505 * \since 12.0.0
4506 *
4507 * \param v_obj A pointer to the object we want printed.
4508 * \param where User data needed by prnt to determine where to put output.
4509 * \param prnt Print output callback function to use.
4510 */
4511static void cdr_master_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt)
4512{
4513 struct cdr_object *cdr = v_obj;
4514 struct cdr_object *it_cdr;
4515
4516 if (!cdr) {
4517 return;
4518 }
4519 for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
4520 prnt(where, "Party A: %s; Party B: %s; Bridge %s\n",
4521 it_cdr->party_a.snapshot->base->name,
4522 it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<unknown>",
4523 it_cdr->bridge);
4524 }
4525}
4526
4527/*!
4528 * \internal
4529 * \brief Print all CDR container object.
4530 * \since 13.19.0
4531 *
4532 * \param v_obj A pointer to the object we want printed.
4533 * \param where User data needed by prnt to determine where to put output.
4534 * \param prnt Print output callback function to use.
4535 */
4536static void cdr_all_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt)
4537{
4538 struct cdr_object *cdr = v_obj;
4539
4540 if (!cdr) {
4541 return;
4542 }
4543 prnt(where, "Party A: %s; Party B: %s; Bridge %s",
4544 cdr->party_a.snapshot->base->name,
4545 cdr->party_b.snapshot ? cdr->party_b.snapshot->base->name : "<unknown>",
4546 cdr->bridge);
4547}
4548
4549/*!
4550 * \brief Checks if CDRs are enabled and enables/disables the necessary options
4551 */
4553{
4554 struct module_config *mod_cfg;
4555
4556 mod_cfg = ao2_global_obj_ref(module_configs);
4557 if (mod_cfg
4558 && ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)) {
4559 if (create_subscriptions()) {
4561 ast_log(AST_LOG_ERROR, "Failed to create Stasis subscriptions\n");
4562 ao2_cleanup(mod_cfg);
4563 return -1;
4564 }
4565 if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4567 } else {
4568 ast_log(LOG_NOTICE, "CDR simple logging enabled.\n");
4569 }
4570 } else {
4572 ast_log(LOG_NOTICE, "CDR logging disabled.\n");
4573 }
4574 ao2_cleanup(mod_cfg);
4575
4576 return mod_cfg ? 0 : -1;
4577}
4578
4579static int unload_module(void)
4580{
4582
4583 return 0;
4584}
4585
4586static int load_module(void)
4587{
4588 struct module_config *mod_cfg = NULL;
4589 if (process_config(0)) {
4591 }
4592
4593 cdr_topic = stasis_topic_create("cdr:aggregator");
4594 if (!cdr_topic) {
4596 }
4597
4599 if (!stasis_router) {
4601 }
4604
4605 if (STASIS_MESSAGE_TYPE_INIT(cdr_sync_message_type)) {
4607 }
4608
4609 mod_cfg = ao2_global_obj_ref(module_configs);
4610
4612
4613 /* Always process dial messages, because even if we ignore most of it, we do want the dial status for the disposition. */
4615 if (!mod_cfg || !ast_test_flag(&mod_cfg->general->settings, CDR_IGNORE_DIAL_CHANGES)) {
4617 } else {
4619 CDR_DEBUG("Dial messages will be mostly ignored\n");
4620 }
4621
4622 /* If explicitly instructed to ignore call state changes, then ignore bridging events, parking, etc. */
4623 if (!mod_cfg || !ast_test_flag(&mod_cfg->general->settings, CDR_IGNORE_STATE_CHANGES)) {
4627 } else {
4628 CDR_DEBUG("All bridge and parking messages will be ignored\n");
4629 }
4630
4632
4633 if (mod_cfg) {
4634 ao2_cleanup(mod_cfg);
4635 } else {
4636 ast_log(LOG_WARNING, "Unable to obtain CDR configuration during module load?\n");
4637 }
4638
4641 if (!active_cdrs_master) {
4643 }
4645
4648 if (!active_cdrs_all) {
4650 }
4652
4654 if (!sched) {
4655 ast_log(LOG_ERROR, "Unable to create schedule context.\n");
4657 }
4658
4661
4663}
4664
4666{
4667 RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
4668
4669 /* Since this is called explicitly during process shutdown, we might not have ever
4670 * been initialized. If so, the config object will be NULL.
4671 */
4672 if (!mod_cfg) {
4673 return;
4674 }
4675
4676 if (cdr_sync_message_type()) {
4677 void *payload;
4678 struct stasis_message *message;
4679
4680 if (!stasis_router) {
4681 return;
4682 }
4683
4684 /* Make sure we have the needed items */
4685 payload = ao2_alloc(sizeof(*payload), NULL);
4686 if (!payload) {
4687 return;
4688 }
4689
4690 ast_debug(1, "CDR Engine termination request received; waiting on messages...\n");
4691
4692 message = stasis_message_create(cdr_sync_message_type(), payload);
4693 if (message) {
4695 }
4697 ao2_cleanup(payload);
4698 }
4699
4700 if (ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4701 cdr_submit_batch(ast_test_flag(&mod_cfg->general->batch_settings.settings, BATCH_MODE_SAFE_SHUTDOWN));
4702 }
4703}
4704
4705static int reload_module(void)
4706{
4707 struct module_config *old_mod_cfg;
4708 struct module_config *mod_cfg;
4709
4710 old_mod_cfg = ao2_global_obj_ref(module_configs);
4711
4712 if (!old_mod_cfg || process_config(1)) {
4713 ao2_cleanup(old_mod_cfg);
4714 return -1;
4715 }
4716
4717 mod_cfg = ao2_global_obj_ref(module_configs);
4718 if (!mod_cfg
4719 || !ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED)
4720 || !ast_test_flag(&mod_cfg->general->settings, CDR_BATCHMODE)) {
4721 /* If batch mode used to be enabled, finalize the batch */
4722 if (ast_test_flag(&old_mod_cfg->general->settings, CDR_BATCHMODE)) {
4724 }
4725 }
4726 ao2_cleanup(mod_cfg);
4727
4728 ao2_cleanup(old_mod_cfg);
4730}
4731
4733 .support_level = AST_MODULE_SUPPORT_CORE,
4734 .load = load_module,
4735 .unload = unload_module,
4737 .load_pri = AST_MODPRI_CORE,
4738 .requires = "extconfig",
ast_mutex_t lock
Definition: app_sla.c:331
#define var
Definition: ast_expr2f.c:605
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_atexit(void(*func)(void))
Register a function to be executed before Asterisk exits.
Definition: clicompat.c:13
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_log
Definition: astobj2.c:42
#define ao2_t_ref(o, delta, tag)
Definition: astobj2.h:460
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
Definition: astobj2.h:901
#define ao2_t_replace(dst, src, tag)
Definition: astobj2.h:504
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
void ao2_container_unregister(const char *name)
Unregister a container for CLI stats and integrity check.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_callback_data(container, flags, cb_fn, arg, data)
Definition: astobj2.h:1723
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
#define ao2_unlink_flags(container, obj, flags)
Remove an object from a container.
Definition: astobj2.h:1600
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition: astobj2.h:1554
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition: astobj2.h:918
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
Definition: astobj2.h:501
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
int ao2_container_register(const char *name, struct ao2_container *self, ao2_prnt_obj_fn *prnt_obj)
Register a container for CLI stats and integrity check.
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition: astobj2.h:859
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
@ OBJ_UNLINK
Definition: astobj2.h:1039
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
void() ao2_prnt_fn(void *where, const char *fmt,...)
Print output.
Definition: astobj2.h:1435
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
Definition: callerid.c:1174
Internal Asterisk hangup causes.
#define AST_CAUSE_CONGESTION
Definition: causes.h:153
#define AST_CAUSE_NO_ROUTE_DESTINATION
Definition: causes.h:100
#define AST_CAUSE_UNREGISTERED
Definition: causes.h:154
#define AST_CAUSE_BUSY
Definition: causes.h:149
#define AST_CAUSE_NO_ANSWER
Definition: causes.h:109
#define AST_CAUSE_NORMAL_CLEARING
Definition: causes.h:106
static void reset_batch(void)
Definition: cdr.c:3792
struct cdr_object_fn_table dial_state_fn_table
The virtual table for the Dial state.
Definition: cdr.c:646
static void finalized_state_init_function(struct cdr_object *cdr)
Definition: cdr.c:2083
struct cdr_object_fn_table single_state_fn_table
The virtual table for the Single state.
Definition: cdr.c:615
static int dial_changes_ignored
Definition: cdr.c:250
static struct aco_type ignore_option
Definition: cdr.c:294
static enum ast_cdr_disposition dial_status_to_disposition(const char *dial_status)
Definition: cdr.c:1867
static int finalized_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
Definition: cdr.c:2088
static int cdr_object_dispatch_all_cb(void *obj, void *arg, int flags)
This dispatches all cdr_object. It should only be used during shutdown, so that we get billing record...
Definition: cdr.c:4325
static int cdr_object_format_property(struct cdr_object *cdr_obj, const char *name, char *value, size_t length)
Format one of the standard properties on a cdr_object.
Definition: cdr.c:3305
static void cdr_object_transition_state_init(struct cdr_object *cdr, struct cdr_object_fn_table *fn_table, int do_init)
Transition a cdr_object to a new state with initiation flag.
Definition: cdr.c:847
static int dialed_pending_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
Definition: cdr.c:2031
#define DEFAULT_BATCH_SIZE
Definition: cdr.c:237
static void handle_parked_call_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Handler for when a channel is parked.
Definition: cdr.c:2814
static struct ast_cdr * cdr_object_create_public_records(struct cdr_object *cdr)
Create a chain of ast_cdr objects from a chain of cdr_object suitable for consumption by the register...
Definition: cdr.c:1326
int ast_cdr_is_enabled(void)
Return TRUE if CDR subsystem is enabled.
Definition: cdr.c:2923
#define MAX_BATCH_SIZE
Definition: cdr.c:238
static struct ast_cli_entry cli_commands[]
Definition: cdr.c:4314
static pthread_t cdr_thread
Definition: cdr.c:397
void ast_cdr_setuserfield(const char *channel_name, const char *userfield)
Set CDR user field for channel (stored in CDR)
Definition: cdr.c:3539
static void cdr_all_unlink(struct cdr_object *cdr)
Definition: cdr.c:1011
static const char *const cdr_readonly_vars[]
Definition: cdr.c:3216
STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_sync_message_type)
A message type used to synchronize with the CDR topic.
static void handle_standard_bridge_enter_message(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel, const struct timeval *event_time)
Handle a bridge enter message for a 'normal' bridge.
Definition: cdr.c:2692
static int process_config(int reload)
Definition: cdr.c:4405
static int dialed_pending_state_process_parking_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Definition: cdr.c:2021
static char * handle_cli_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cdr.c:4177
static struct cdr_object * cdr_object_alloc(struct ast_channel_snapshot *chan, const struct timeval *event_time)
cdr_object constructor
Definition: cdr.c:1079
int ast_cdr_modifier_register(const char *name, const char *desc, ast_cdrbe be)
Register a CDR modifier.
Definition: cdr.c:3010
static void cdr_get_tv(struct timeval when, const char *fmt, char *buf, int bufsize)
Definition: cdr.c:3097
static int single_state_bridge_enter_comparison(struct cdr_object *cdr, struct cdr_object *cand_cdr)
Handle a comparison between our cdr_object and a cdr_object already in the bridge while in the Single...
Definition: cdr.c:1731
static struct cdr_object * cdr_object_create_and_append(struct cdr_object *cdr, const struct timeval *event_time)
Create a new cdr_object and append it to an existing chain.
Definition: cdr.c:1116
static const char * ignore_categories[]
Definition: cdr.c:281
static void cdr_all_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt)
Definition: cdr.c:4536
static long cdr_object_get_duration(struct cdr_object *cdr)
Definition: cdr.c:1266
void ast_cdr_free(struct ast_cdr *cdr)
Free a CDR record.
Definition: cdr.c:3473
struct cdr_object_fn_table dialed_pending_state_fn_table
The virtual table for the Dialed Pending state.
Definition: cdr.c:679
static void bridge_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
Definition: cdr.c:2041
void ast_cdr_set_config(struct ast_cdr_config *config)
Set the current CDR configuration.
Definition: cdr.c:2902
#define DEFAULT_BATCHMODE
Definition: cdr.c:228
static ast_cond_t cdr_pending_cond
Definition: cdr.c:404
struct stasis_message_router * ast_cdr_message_router(void)
Return the message router for the CDR engine.
Definition: cdr.c:4356
static void single_state_init_function(struct cdr_object *cdr)
Definition: cdr.c:1678
static int create_subscriptions(void)
Create the Stasis subcriptions for CDRs.
Definition: cdr.c:4379
static void cdr_object_finalize(struct cdr_object *cdr)
Finalize a CDR.
Definition: cdr.c:1479
static struct ast_sched_context * sched
Scheduler items.
Definition: cdr.c:394
static int base_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Definition: cdr.c:1640
static int cdr_object_update_party_b(void *obj, void *arg, void *data, int flags)
Definition: cdr.c:2272
#define DEFAULT_IGNORE_STATE_CHANGES
Definition: cdr.c:234
static ast_mutex_t cdr_batch_lock
Lock protecting modifications to the batch queue.
Definition: cdr.c:400
process_bridge_enter_results
Return types for process_bridge_enter functions.
Definition: cdr.c:433
@ BRIDGE_ENTER_ONLY_PARTY
Definition: cdr.c:437
@ BRIDGE_ENTER_NO_PARTY_B
Definition: cdr.c:445
@ BRIDGE_ENTER_NEED_CDR
Definition: cdr.c:449
@ BRIDGE_ENTER_OBTAINED_PARTY_B
Definition: cdr.c:441
int ast_cdr_modifier_unregister(const char *name)
Unregister a CDR modifier.
Definition: cdr.c:3055
static int cdr_generic_register(struct be_list *generic_list, const char *name, const char *desc, ast_cdrbe be)
Definition: cdr.c:2964
static void cdr_detach(struct ast_cdr *cdr)
Definition: cdr.c:3903
static int cdr_object_finalize_party_b(void *obj, void *arg, void *data, int flags)
Definition: cdr.c:2248
static struct cdr_batch * batch
static void bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *base_cand_cdr)
Process a single bridge_candidate.
Definition: cdr.c:2566
struct cdr_object_fn_table bridge_state_fn_table
The virtual table for the Bridged state.
Definition: cdr.c:701
static char * handle_cli_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cdr.c:3991
static void cli_show_channels(struct ast_cli_args *a)
Definition: cdr.c:4053
#define FORMAT_STRING
static struct stasis_forward * bridge_subscription
Our subscription for bridges.
Definition: cdr.c:416
int ast_cdr_clear_property(const char *channel_name, enum ast_cdr_options option)
Clear a property on a CDR for a channel.
Definition: cdr.c:3637
static int cdr_object_select_all_by_name_cb(void *obj, void *arg, int flags)
Definition: cdr.c:3188
static int cdr_sched
Definition: cdr.c:395
int ast_cdr_setvar(const char *channel_name, const char *name, const char *value)
Set a variable on a CDR.
Definition: cdr.c:3240
void ast_cdr_format_var(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int raw)
Format a CDR variable from an already posted CDR.
Definition: cdr.c:3112
static const char * cdr_format_var_internal(struct ast_cdr *cdr, const char *name)
Definition: cdr.c:3080
static int cdr_all_hash_fn(const void *obj, const int flags)
Definition: cdr.c:931
static int filter_channel_snapshot(struct ast_channel_snapshot *snapshot)
Definition: cdr.c:2103
static enum process_bridge_enter_results base_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Definition: cdr.c:1650
static void cdr_object_dispatch(struct cdr_object *cdr)
Dispatch a CDR.
Definition: cdr.c:1425
static struct stasis_forward * channel_subscription
Our subscription for channels.
Definition: cdr.c:419
#define DEFAULT_UNANSWERED
Definition: cdr.c:229
void ast_cdr_engine_term(void)
Definition: cdr.c:4665
static int base_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
Definition: cdr.c:1645
static struct aco_file module_file_conf
The file definition.
Definition: cdr.c:306
static int base_process_parked_channel(struct cdr_object *cdr, struct ast_parked_call_payload *parking_info)
Definition: cdr.c:1656
static char * handle_cli_submit(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cdr.c:4277
static struct aco_type general_option
The type definition for general options.
Definition: cdr.c:272
static int cdr_master_cmp_fn(void *obj, void *arg, int flags)
Definition: cdr.c:897
struct ast_cdr * ast_cdr_alloc(void)
Allocate a CDR record.
Definition: cdr.c:3484
#define MAX_BATCH_TIME
Definition: cdr.c:240
static void cdr_object_swap_snapshot(struct cdr_object_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
Swap an old cdr_object_snapshot's ast_channel_snapshot for a new ast_channel_snapshot.
Definition: cdr.c:1570
struct cdr_object_fn_table finalized_state_fn_table
The virtual table for the finalized state.
Definition: cdr.c:736
static void handle_bridge_leave_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Handler for when a channel leaves a bridge.
Definition: cdr.c:2467
#define cdr_set_debug_mode(mod_cfg)
Definition: cdr.c:244
static AO2_GLOBAL_OBJ_STATIC(module_configs)
The container for the module configuration.
int ast_cdr_backend_unsuspend(const char *name)
Unsuspend a CDR backend.
Definition: cdr.c:2946
static char * cli_complete_show(struct ast_cli_args *a)
Complete user input for 'cdr show'.
Definition: cdr.c:4032
static void cdr_object_check_party_a_hangup(struct cdr_object *cdr)
Check to see if a CDR needs to move to the finalized state because its Party A hungup.
Definition: cdr.c:1516
static void module_config_destructor(void *obj)
Dispose of a module config object.
Definition: cdr.c:331
static struct stasis_message_router * stasis_router
Message router for stasis messages regarding channel state.
Definition: cdr.c:413
static int check_new_cdr_needed(struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
Determine if we need to add a new CDR based on snapshots.
Definition: cdr.c:2301
static void handle_channel_snapshot_update_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Handler for channel snapshot update messages.
Definition: cdr.c:2329
static int dial_status_end(const char *dialstatus)
Definition: cdr.c:2128
static int ast_cdr_generic_unregister(struct be_list *generic_list, const char *name)
Definition: cdr.c:3015
struct cdr_object_fn_table parked_state_fn_table
The virtual table for the Parked state.
Definition: cdr.c:720
static void single_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
Definition: cdr.c:1684
static int cdr_toggle_runtime_options(void)
Checks if CDRs are enabled and enables/disables the necessary options.
Definition: cdr.c:4552
static void handle_bridge_enter_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: cdr.c:2772
static void handle_cdr_sync_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Handler for a synchronization message.
Definition: cdr.c:2882
static int copy_variables(struct varshead *to_list, struct varshead *from_list)
Copy variables from one list to another.
Definition: cdr.c:788
static int reload_module(void)
Definition: cdr.c:4705
static void finalize_batch_mode(void)
Definition: cdr.c:4342
#define CDR_DEBUG(fmt,...)
Definition: cdr.c:252
int ast_cdr_fork(const char *channel_name, struct ast_flags *options)
Fork a CDR.
Definition: cdr.c:3699
static int dial_state_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
Definition: cdr.c:1887
static void cdr_object_check_party_a_answer(struct cdr_object *cdr)
Check to see if a CDR needs to be answered based on its Party A. Note that this is safe to call as mu...
Definition: cdr.c:1533
static void set_variable(struct varshead *headp, const char *name, const char *value)
Definition: cdr.c:1301
static int filter_bridge_messages(struct ast_bridge_snapshot *bridge)
Filter bridge messages based on bridge technology.
Definition: cdr.c:2450
static int init_batch(void)
Definition: cdr.c:3800
static int submit_scheduled_batch(const void *data)
Definition: cdr.c:3866
static struct aco_type * general_options[]
Definition: cdr.c:316
static void start_batch_mode(void)
Definition: cdr.c:3887
static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
Definition: cdr.c:1579
int ast_cdr_getvar(const char *channel_name, const char *name, char *value, size_t length)
Retrieve a CDR variable from a channel's current CDR.
Definition: cdr.c:3386
int ast_cdr_unregister(const char *name)
Unregister a CDR handling engine.
Definition: cdr.c:3050
static void cdr_object_snapshot_copy(struct cdr_object_snapshot *dst, struct cdr_object_snapshot *src)
Copy a snapshot and its details.
Definition: cdr.c:833
static void cdr_object_format_var_internal(struct cdr_object *cdr, const char *name, char *value, size_t length)
Format a variable on a cdr_object.
Definition: cdr.c:3288
static int cdr_object_update_party_b_userfield_cb(void *obj, void *arg, void *data, int flags)
Callback used to update the userfield on Party B on all CDRs.
Definition: cdr.c:3517
static void dial_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
Definition: cdr.c:1841
static void cdr_all_relink(struct cdr_object *cdr)
Definition: cdr.c:990
static int dial_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
Definition: cdr.c:1855
static void handle_parking_bridge_enter_message(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel, const struct timeval *event_time)
Handle entering into a parking bridge.
Definition: cdr.c:2650
#define DEFAULT_INITIATED_SECONDS
Definition: cdr.c:232
static void cdr_master_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt)
Definition: cdr.c:4511
int ast_cdr_serialize_variables(const char *channel_name, struct ast_str **buf, char delim, char sep)
Serializes all the data and variables for a current CDR record.
Definition: cdr.c:3415
static int bridge_state_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Definition: cdr.c:2054
static struct stasis_forward * parking_subscription
Our subscription for parking.
Definition: cdr.c:422
static void cdr_enable_batch_mode(struct ast_cdr_config *config)
Definition: cdr.c:4484
static long cdr_object_get_billsec(struct cdr_object *cdr)
Compute the billsec for a cdr_object.
Definition: cdr.c:1274
static struct ao2_container * active_cdrs_master
A container of the active master CDRs indexed by Party A channel uniqueid.
Definition: cdr.c:407
static int global_cdr_sequence
The global sequence counter used for CDRs.
Definition: cdr.c:391
#define DEFAULT_IGNORE_DIAL_CHANGES
Definition: cdr.c:235
static int cdr_all_cmp_fn(void *obj, void *arg, int flags)
Definition: cdr.c:955
static void * do_batch_backend_process(void *data)
Definition: cdr.c:3811
const char * ast_cdr_disp2str(int disposition)
Disposition to a string.
Definition: cdr.c:3492
static int is_cdr_flag_set(unsigned int cdr_flag)
Definition: cdr.c:1166
static int snapshot_is_dialed(struct ast_channel_snapshot *snapshot)
Return whether or not a ast_channel_snapshot is for a channel that was created as the result of a dia...
Definition: cdr.c:1218
static void cdr_object_set_disposition(struct cdr_object *cdr, int hangupcause)
Set the disposition on a cdr_object based on a hangupcause code.
Definition: cdr.c:1441
static struct ao2_container * active_cdrs_all
A container of all active CDRs with a Party B indexed by Party B channel name.
Definition: cdr.c:410
static void bridge_candidate_add_to_cdr(struct cdr_object *cdr, struct cdr_object_snapshot *party_b)
Definition: cdr.c:2535
static struct stasis_topic * cdr_topic
The parent topic for all topics we want to aggregate for CDRs.
Definition: cdr.c:425
static char * handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cdr.c:4207
int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
Register a CDR handling engine.
Definition: cdr.c:3005
static int snapshot_cep_changed(struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
Return whether or not a channel has changed its state in the dialplan, subject to endbeforehexten log...
Definition: cdr.c:1187
#define DEFAULT_BATCH_SAFE_SHUTDOWN
Definition: cdr.c:242
static void handle_dial_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Handler for Stasis-Core dial messages.
Definition: cdr.c:2143
#define DEFAULT_BATCH_TIME
Definition: cdr.c:239
static int filter_channel_snapshot_message(struct ast_channel_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
Definition: cdr.c:2112
static int load_module(void)
Definition: cdr.c:4586
static void cli_show_channel(struct ast_cli_args *a)
Definition: cdr.c:4117
static int cdr_object_get_by_name_cb(void *obj, void *arg, int flags)
Definition: cdr.c:3204
static struct cdr_object * cdr_object_get_by_name(const char *name)
Definition: cdr.c:3374
int ast_cdr_backend_suspend(const char *name)
Suspend a CDR backend temporarily.
Definition: cdr.c:2928
static void cdr_engine_shutdown(void)
Definition: cdr.c:4453
static ast_mutex_t cdr_pending_lock
These are used to wake up the CDR thread when there's work to do.
Definition: cdr.c:403
static void post_cdr(struct ast_cdr *cdr)
Definition: cdr.c:3570
static int unload_module(void)
Definition: cdr.c:4579
#define DEFAULT_BATCH_SCHEDULER_ONLY
Definition: cdr.c:241
static int single_state_process_parking_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Definition: cdr.c:1832
struct ast_cdr_config * ast_cdr_get_config(void)
Obtain the current CDR configuration.
Definition: cdr.c:2888
static enum process_bridge_enter_results dialed_pending_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Definition: cdr.c:2015
#define DEFAULT_CHANNEL_ENABLED
Definition: cdr.c:233
#define DEFAULT_ENABLED
Definition: cdr.c:227
static void * module_config_alloc(void)
Create a new module config object.
Definition: cdr.c:342
static struct cdr_object_snapshot * cdr_object_pick_party_a(struct cdr_object_snapshot *left, struct cdr_object_snapshot *right)
Given two CDR snapshots, figure out who should be Party A for the resulting CDR.
Definition: cdr.c:1231
static void cdr_object_update_cid(struct cdr_object_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
Set Caller ID information on a CDR.
Definition: cdr.c:1545
static void free_variables(struct varshead *headp)
Delete all variables from a variable list.
Definition: cdr.c:819
static int single_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
Definition: cdr.c:1692
static int cdr_object_party_b_left_bridge_cb(void *obj, void *arg, void *data, int flags)
Callback used to notify CDRs of a Party B leaving the bridge.
Definition: cdr.c:2425
#define TITLE_STRING
static int cdr_master_hash_fn(const void *obj, const int flags)
Definition: cdr.c:873
static int parked_state_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Definition: cdr.c:2071
static void destroy_subscriptions(void)
Destroy the active Stasis subscriptions.
Definition: cdr.c:4369
static void cdr_submit_batch(int shutdown)
Definition: cdr.c:3828
static void cdr_object_dtor(void *obj)
cdr_object Destructor
Definition: cdr.c:1038
static void module_config_post_apply(void)
Definition: cdr.c:318
static int dialed_pending_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
Definition: cdr.c:1990
#define DEFAULT_END_BEFORE_H_EXTEN
Definition: cdr.c:231
static ast_mutex_t cdr_sched_lock
Definition: cdr.c:396
static void cdr_object_transition_state(struct cdr_object *cdr, struct cdr_object_fn_table *fn_table)
Transition a cdr_object to a new state.
Definition: cdr.c:864
static int cdr_debug_enabled
Definition: cdr.c:249
static void handle_bridge_pairings(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge)
Handle creating bridge pairings for the cdr_object that just entered a bridge.
Definition: cdr.c:2624
struct ast_cdr * ast_cdr_dup(struct ast_cdr *cdr)
Duplicate a public CDR.
Definition: cdr.c:3060
static void * do_cdr(void *data)
Definition: cdr.c:3965
CONFIG_INFO_CORE("cdr", cfg_info, module_configs, module_config_alloc,.files=ACO_FILES(&module_file_conf),.post_apply_config=module_config_post_apply,)
int ast_cdr_reset(const char *channel_name, int keep_variables)
Reset the detail record.
Definition: cdr.c:3660
int ast_cdr_set_property(const char *channel_name, enum ast_cdr_options option)
Set a property on a CDR for a channel.
Definition: cdr.c:3610
static enum process_bridge_enter_results dial_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Definition: cdr.c:1919
static enum process_bridge_enter_results single_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Definition: cdr.c:1775
Call Detail Record API.
@ CDR_UNANSWERED
Definition: cdr.h:222
@ CDR_IGNORE_STATE_CHANGES
Definition: cdr.h:228
@ CDR_INITIATED_SECONDS
Definition: cdr.h:225
@ CDR_ENABLED
Definition: cdr.h:220
@ CDR_CHANNEL_DEFAULT_ENABLED
Definition: cdr.h:227
@ CDR_END_BEFORE_H_EXTEN
Definition: cdr.h:224
@ CDR_IGNORE_DIAL_CHANGES
Definition: cdr.h:229
@ CDR_BATCHMODE
Definition: cdr.h:221
@ CDR_CONGESTION
Definition: cdr.h:223
@ BATCH_MODE_SAFE_SHUTDOWN
Definition: cdr.h:235
@ BATCH_MODE_SCHEDULER_ONLY
Definition: cdr.h:234
ast_cdr_disposition
CDR Flags - Disposition.
Definition: cdr.h:256
@ AST_CDR_CONGESTION
Definition: cdr.h:262
@ AST_CDR_NULL
Definition: cdr.h:258
@ AST_CDR_NOANSWER
Definition: cdr.h:257
@ AST_CDR_ANSWERED
Definition: cdr.h:261
@ AST_CDR_BUSY
Definition: cdr.h:260
@ AST_CDR_FAILED
Definition: cdr.h:259
int(* ast_cdrbe)(struct ast_cdr *cdr)
CDR backend callback.
Definition: cdr.h:461
ast_cdr_options
CDR manipulation options. Certain function calls will manipulate the state of a CDR object based on t...
Definition: cdr.h:242
@ AST_CDR_FLAG_DISABLE_ALL
Definition: cdr.h:245
@ AST_CDR_LOCK_APP
Definition: cdr.h:250
@ AST_CDR_FLAG_FINALIZE
Definition: cdr.h:247
@ AST_CDR_FLAG_DISABLE
Definition: cdr.h:244
@ AST_CDR_FLAG_PARTY_A
Definition: cdr.h:246
@ AST_CDR_FLAG_KEEP_VARS
Definition: cdr.h:243
@ AST_CDR_FLAG_RESET
Definition: cdr.h:249
@ AST_CDR_FLAG_SET_ANSWER
Definition: cdr.h:248
static const char cdr_config[]
Definition: cdr_radius.c:86
static const char desc[]
Definition: cdr_radius.c:84
static struct cdr_tds_config * settings
Definition: cdr_tds.c:95
static PGresult * result
Definition: cel_pgsql.c:84
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2365
static const char config[]
Definition: chan_ooh323.c:111
General Asterisk PBX channel definitions.
@ AST_CHAN_TP_INTERNAL
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition: channel.h:971
#define AST_NUM_CHANNEL_BUCKETS
Definition: channel.h:155
const char * ast_channel_amaflags2string(enum ama_flags flags)
Convert the enum representation of an AMA flag to a string representation.
Definition: channel.c:4372
@ AST_SOFTHANGUP_HANGUP_EXEC
Definition: channel.h:1154
@ AST_FLAG_OUTGOING
Definition: channel.h:999
@ AST_FLAG_DEAD
Definition: channel.h:1045
@ AST_FLAG_SUBROUTINE_EXEC
Definition: channel.h:1058
@ AST_FLAG_ORIGINATED
Definition: channel.h:1039
#define AST_MAX_USER_FIELD
Definition: channel.h:174
@ AST_STATE_UP
Definition: channelstate.h:42
const char * ast_var_name(const struct ast_var_t *var)
Definition: chanvars.c:60
#define ast_var_assign(name, value)
Definition: chanvars.h:40
const char * ast_var_value(const struct ast_var_t *var)
Definition: chanvars.c:80
void ast_var_delete(struct ast_var_t *var)
Definition: extconf.c:2471
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition: main/cli.c:2758
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define ESS(x)
Definition: cli.h:59
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static void update(int code_size, int y, int wi, int fi, int dq, int sr, int dqsez, struct g726_state *state_ptr)
Definition: codec_g726.c:367
Configuration option-handling.
@ ACO_EXACT
int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
Set all default options of obj.
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
@ ACO_PROCESS_ERROR
Their was an error and no changes were applied.
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
#define ACO_FILES(...)
@ OPT_UINT_T
Type for default option handler for unsigned integers.
@ OPT_BOOLFLAG_T
Type for default option handler for bools (ast_true/ast_false) that are stored in a flag.
@ ACO_GLOBAL
@ ACO_IGNORE
@ ACO_WHITELIST_ARRAY
@ ACO_WHITELIST_EXACT
enum aco_process_status aco_process_config(struct aco_info *info, int reload)
Process a config info via the options registered with an aco_info.
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
char * be
Definition: eagi_proxy.c:73
char * end
Definition: eagi_proxy.c:73
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static const char name[]
Definition: format_mp3.c:68
struct stasis_topic * ast_parking_topic(void)
accessor for the parking stasis topic
Definition: parking.c:67
struct stasis_topic * ast_channel_topic_all(void)
A topic which publishes the events for all channels.
struct stasis_message_type * ast_parked_call_type(void)
accessor for the parked call stasis message type
struct ast_channel_snapshot * ast_multi_channel_blob_get_channel(struct ast_multi_channel_blob *obj, const char *role)
Retrieve a channel snapshot associated with a specific role from a ast_multi_channel_blob.
struct stasis_message_type * ast_channel_dial_type(void)
Message type for when a channel dials another channel.
struct stasis_message_type * ast_channel_snapshot_type(void)
Message type for ast_channel_snapshot_update.
struct ast_json * ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj)
Retrieve the JSON blob from a ast_multi_channel_blob. Returned ast_json is still owned by obj.
Configuration File Parser.
#define AST_LOG_WARNING
#define AST_LOG_ERROR
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_NOTICE
#define LOG_WARNING
Asterisk JSON abstraction layer.
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:407
A set of macros to manage forward-linked lists.
#define AST_RWLIST_EMPTY
Definition: linkedlists.h:452
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized.
Definition: linkedlists.h:333
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_RWLIST_REMOVE
Definition: linkedlists.h:885
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:494
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:718
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_RWLIST_ENTRY
Definition: linkedlists.h:415
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
Asterisk locking-related definitions:
#define ast_cond_destroy(cond)
Definition: lock.h:202
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:604
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define ast_cond_init(cond, attr)
Definition: lock.h:201
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:206
#define ast_mutex_unlock(a)
Definition: lock.h:190
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
pthread_cond_t ast_cond_t
Definition: lock.h:178
#define ast_mutex_lock(a)
Definition: lock.h:189
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:520
#define ast_cond_signal(cond)
Definition: lock.h:203
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:317
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition: module.h:316
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODPRI_CORE
Definition: module.h:324
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_FAILURE
Module could not be loaded properly.
Definition: module.h:102
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
def info(msg)
Call Parking API.
@ PARKED_CALL
Definition: parking.h:47
static int total
Definition: res_adsi.c:970
static int reload(void)
struct stasis_forward * sub
Definition: res_corosync.c:240
#define NULL
Definition: resample.c:96
Scheduler Routines (derived from cheops)
#define AST_SCHED_DEL(sched, id)
Remove a scheduler entry.
Definition: sched.h:46
long ast_sched_when(struct ast_sched_context *con, int id)
Returns the number of seconds before an event takes place.
Definition: sched.c:851
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:271
int ast_sched_runq(struct ast_sched_context *con)
Runs the queue.
Definition: sched.c:786
int ast_sched_add_variable(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data, int variable) attribute_warn_unused_result
Adds a scheduled event with rescheduling support.
Definition: sched.c:526
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition: sched.c:238
int ast_sched_wait(struct ast_sched_context *con) attribute_warn_unused_result
Determines number of seconds until the next outstanding event to take place.
Definition: sched.c:433
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515
struct stasis_forward * stasis_forward_cancel(struct stasis_forward *forward)
Definition: stasis.c:1548
struct stasis_topic * stasis_topic_create(const char *name)
Create a new topic.
Definition: stasis.c:617
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
struct stasis_forward * stasis_forward_all(struct stasis_topic *from_topic, struct stasis_topic *to_topic)
Create a subscription which forwards all messages from one topic to another.
Definition: stasis.c:1578
const struct timeval * stasis_message_timestamp(const struct stasis_message *msg)
Get the time when a message was created.
struct stasis_message_type * ast_channel_entered_bridge_type(void)
Message type for ast_channel enter bridge blob messages.
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
struct stasis_message_type * ast_channel_left_bridge_type(void)
Message type for ast_channel leave bridge blob messages.
int stasis_message_router_set_congestion_limits(struct stasis_message_router *router, long low_water, long high_water)
Set the high and low alert water marks of the stasis message router.
#define stasis_message_router_create(topic)
Create a new message router object.
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.
void stasis_message_router_unsubscribe_and_join(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic, blocking until the final message has been processed.
void stasis_message_router_publish_sync(struct stasis_message_router *router, struct stasis_message *message)
Publish a message to a message router's subscription synchronously.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:693
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1303
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
The representation of a single configuration file to be processed.
const char * filename
Type information about a category-level configurable object.
enum aco_type_t type
enum aco_category_op category_match
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Blob of data associated with a bridge.
Structure that contains a snapshot of information about a bridge.
Definition: bridge.h:314
const ast_string_field uniqueid
Definition: bridge.h:328
const ast_string_field technology
Definition: bridge.h:328
struct ao2_container * channels
Definition: bridge.h:331
const ast_string_field subclass
Definition: bridge.h:328
struct ast_flags settings
Definition: cdr.h:272
The global options available for CDRs.
Definition: cdr.h:267
struct ast_flags settings
Definition: cdr.h:268
struct ast_cdr_config::batch_settings batch_settings
Responsible for call detail data.
Definition: cdr.h:279
char dstchannel[AST_MAX_EXTENSION]
Definition: cdr.h:291
long int disposition
Definition: cdr.h:307
char lastdata[AST_MAX_EXTENSION]
Definition: cdr.h:295
char linkedid[AST_MAX_UNIQUEID]
Definition: cdr.h:319
char userfield[AST_MAX_USER_FIELD]
Definition: cdr.h:321
long int billsec
Definition: cdr.h:305
struct timeval answer
Definition: cdr.h:299
char channel[AST_MAX_EXTENSION]
Definition: cdr.h:289
char peeraccount[AST_MAX_ACCOUNT_CODE]
Definition: cdr.h:313
struct ast_cdr * next
Definition: cdr.h:328
long int duration
Definition: cdr.h:303
struct varshead varshead
Definition: cdr.h:326
long int amaflags
Definition: cdr.h:309
char src[AST_MAX_EXTENSION]
Definition: cdr.h:283
char dst[AST_MAX_EXTENSION]
Definition: cdr.h:285
char clid[AST_MAX_EXTENSION]
Definition: cdr.h:281
char uniqueid[AST_MAX_UNIQUEID]
Definition: cdr.h:317
int sequence
Definition: cdr.h:323
struct timeval start
Definition: cdr.h:297
char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: cdr.h:311
char lastapp[AST_MAX_EXTENSION]
Definition: cdr.h:293
char dcontext[AST_MAX_EXTENSION]
Definition: cdr.h:287
struct timeval end
Definition: cdr.h:301
const ast_string_field accountcode
const ast_string_field uniqueid
const ast_string_field name
const ast_string_field dialed_subaddr
const ast_string_field number
const ast_string_field name
const ast_string_field subaddr
const ast_string_field dnid
const ast_string_field data
const ast_string_field context
const ast_string_field exten
const ast_string_field appl
Structure representing a change of snapshot of channel state.
Structure representing a snapshot of channel state.
struct ast_channel_snapshot_dialplan * dialplan
struct ast_channel_snapshot_peer * peer
struct ast_channel_snapshot_bridge * bridge
struct ast_channel_snapshot_base * base
enum ast_channel_state state
struct ast_flags softhangup_flags
struct ast_channel_snapshot_caller * caller
struct ast_flags flags
struct ast_channel_snapshot_hangup * hangup
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Structure used to handle boolean flags.
Definition: utils.h:199
unsigned int flags
Definition: utils.h:200
Abstract JSON element (object, array, string, int, ...).
A multi channel blob data structure for multi_channel_blob stasis messages.
A parked call message payload.
Definition: parking.h:59
unsigned int parkingspace
Definition: parking.h:65
const ast_string_field parkinglot
Definition: parking.h:69
struct ast_channel_snapshot * parkee
Definition: parking.h:60
enum ast_parked_call_event_type event_type
Definition: parking.h:62
Support for dynamic strings.
Definition: strings.h:623
struct ast_var_t::@211 entries
List of registered backends.
Definition: cdr.c:372
const struct timeval * lastevent
Definition: cdr.c:2421
struct ast_bridge_snapshot * bridge
Definition: cdr.c:2419
struct ast_channel_snapshot * channel
Definition: cdr.c:2420
Queued CDR waiting to be batched.
Definition: cdr.c:378
struct ast_cdr * cdr
Definition: cdr.c:379
struct cdr_batch_item * next
Definition: cdr.c:380
The actual batch queue.
Definition: cdr.c:384
int size
Definition: cdr.c:385
struct cdr_batch_item * head
Definition: cdr.c:386
struct cdr_batch_item * tail
Definition: cdr.c:387
Registration object for CDR backends.
Definition: cdr.c:363
char name[20]
Definition: cdr.c:364
ast_cdrbe be
Definition: cdr.c:366
char desc[80]
Definition: cdr.c:365
A virtual table used for cdr_object.
Definition: cdr.c:458
int(*const process_party_a)(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
Process a Party A update for the cdr_object.
Definition: cdr.c:479
int(*const process_dial_end)(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
Process the end of a dial. At the end of a dial, a CDR can be transitioned into one of two states - D...
Definition: cdr.c:522
void(*const process_party_b)(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
Process a Party B update for the cdr_object.
Definition: cdr.c:488
enum process_bridge_enter_results(*const process_bridge_enter)(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Process the entering of a bridge by this CDR. The purpose of this callback is to have the CDR prepare...
Definition: cdr.c:545
int(*const process_dial_begin)(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
Process the beginning of a dial. A dial message implies one of two things: The cdr_object's Party A h...
Definition: cdr.c:504
int(*const process_bridge_leave)(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Process the leaving of a bridge by this CDR.
Definition: cdr.c:575
const char * name
Name of the subclass.
Definition: cdr.c:460
int(*const process_parking_bridge_enter)(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
Process entering into a parking bridge.
Definition: cdr.c:561
void(*const init_function)(struct cdr_object *cdr)
An initialization function. This will be called automatically when a cdr_object is switched to this t...
Definition: cdr.c:469
int(*const process_parked_channel)(struct cdr_object *cdr, struct ast_parked_call_payload *parking_info)
Process an update informing us that the channel got itself parked.
Definition: cdr.c:588
A wrapper object around a snapshot. Fields that are mutable by the CDR engine are replicated here.
Definition: cdr.c:746
char userfield[AST_MAX_USER_FIELD]
Definition: cdr.c:748
struct varshead variables
Definition: cdr.c:750
struct ast_channel_snapshot * snapshot
Definition: cdr.c:747
unsigned int flags
Definition: cdr.c:749
An in-memory representation of an active CDR.
Definition: cdr.c:754
unsigned int sequence
Definition: cdr.c:764
struct cdr_object_fn_table * fn_table
Definition: cdr.c:757
enum ast_cdr_disposition disposition
Definition: cdr.c:759
const ast_string_field linkedid
Definition: cdr.c:776
struct cdr_object * next
Definition: cdr.c:777
const ast_string_field party_b_name
Definition: cdr.c:776
struct timeval answer
Definition: cdr.c:761
struct cdr_object_snapshot party_a
Definition: cdr.c:755
const ast_string_field uniqueid
Definition: cdr.c:776
struct timeval lastevent
Definition: cdr.c:763
struct cdr_object * last
Definition: cdr.c:778
const ast_string_field data
Definition: cdr.c:776
const ast_string_field context
Definition: cdr.c:776
const ast_string_field exten
Definition: cdr.c:776
int is_root
Definition: cdr.c:779
const ast_string_field name
Definition: cdr.c:776
struct timeval start
Definition: cdr.c:760
struct ast_flags flags
Definition: cdr.c:765
const ast_string_field bridge
Definition: cdr.c:776
struct timeval end
Definition: cdr.c:762
const ast_string_field appl
Definition: cdr.c:776
struct cdr_object_snapshot party_b
Definition: cdr.c:756
List of registered modifiers.
Definition: cdr.c:375
The configuration settings for this module.
Definition: cdr.c:264
struct ast_cdr_config * general
Definition: cdr.c:265
const char * userfield
Definition: cdr.c:3513
const char * channel_name
Definition: cdr.c:3512
Definition: sched.c:76
Forwarding information.
Definition: stasis.c:1531
Definition: ast_expr2.c:325
int value
Definition: syslog.c:37
An API for managing task processing threads that can be shared across modules.
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL
Definition: taskprocessor.h:64
static struct test_options options
static struct test_val a
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
Definition: time.h:282
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:117
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2282
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
Utility functions.
#define ast_test_flag(p, flag)
Definition: utils.h:63
#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
#define ast_assert(a)
Definition: utils.h:739
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:592
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define ast_pthread_create_detached_background(a, b, c, d)
Definition: utils.h:597
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ARRAY_LEN(a)
Definition: utils.h:666
#define ast_copy_flags(dest, src, flagz)
Definition: utils.h:84
#define AST_FLAGS_ALL
Definition: utils.h:196