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