mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-05 20:20:07 +00:00
This patch adds a sequence field to CDRs that can be combined with the linkedid or uniqueid field to uniquely identify a CDR.
(closes issue #15180) Reported by: Nick_Lewis Patches: cdr-sequence10.diff uploaded by mnicholson (license 96) Tested by: mnicholson git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@227435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
2
CHANGES
2
CHANGES
@@ -277,6 +277,8 @@ CDR
|
|||||||
* Multiple files and formats can now be specified in cdr_custom.conf.
|
* Multiple files and formats can now be specified in cdr_custom.conf.
|
||||||
* cdr_syslog has been added which allows CDRs to be written directly to syslog.
|
* cdr_syslog has been added which allows CDRs to be written directly to syslog.
|
||||||
See configs/cdr_syslog.conf.sample for more information.
|
See configs/cdr_syslog.conf.sample for more information.
|
||||||
|
* A 'sequence' field has been added to CDRs which can be combined with
|
||||||
|
linkedid or uniqueid to uniquely identify a CDR.
|
||||||
|
|
||||||
Calendaring for Asterisk
|
Calendaring for Asterisk
|
||||||
------------------------
|
------------------------
|
||||||
|
@@ -184,7 +184,7 @@ static void ast_cdr_fork(struct ast_channel *chan, struct ast_flags optflags, ch
|
|||||||
while (cdr->next)
|
while (cdr->next)
|
||||||
cdr = cdr->next;
|
cdr = cdr->next;
|
||||||
|
|
||||||
if (!(newcdr = ast_cdr_dup(cdr)))
|
if (!(newcdr = ast_cdr_dup_unique(cdr)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ast_cdr_append(cdr, newcdr);
|
ast_cdr_append(cdr, newcdr);
|
||||||
|
@@ -7,6 +7,6 @@
|
|||||||
; Master.csv, Simple.csv, or both.
|
; Master.csv, Simple.csv, or both.
|
||||||
;
|
;
|
||||||
;[mappings]
|
;[mappings]
|
||||||
;Master.csv => ${CSV_QUOTE(${CDR(clid)})},${CSV_QUOTE(${CDR(src)})},${CSV_QUOTE(${CDR(dst)})},${CSV_QUOTE(${CDR(dcontext)})},${CSV_QUOTE(${CDR(channel)})},${CSV_QUOTE(${CDR(dstchannel)})},${CSV_QUOTE(${CDR(lastapp)})},${CSV_QUOTE(${CDR(lastdata)})},${CSV_QUOTE(${CDR(start)})},${CSV_QUOTE(${CDR(answer)})},${CSV_QUOTE(${CDR(end)})},${CSV_QUOTE(${CDR(duration)})},${CSV_QUOTE(${CDR(billsec)})},${CSV_QUOTE(${CDR(disposition)})},${CSV_QUOTE(${CDR(amaflags)})},${CSV_QUOTE(${CDR(accountcode)})},${CSV_QUOTE(${CDR(uniqueid)})},${CSV_QUOTE(${CDR(userfield)})}
|
;Master.csv => ${CSV_QUOTE(${CDR(clid)})},${CSV_QUOTE(${CDR(src)})},${CSV_QUOTE(${CDR(dst)})},${CSV_QUOTE(${CDR(dcontext)})},${CSV_QUOTE(${CDR(channel)})},${CSV_QUOTE(${CDR(dstchannel)})},${CSV_QUOTE(${CDR(lastapp)})},${CSV_QUOTE(${CDR(lastdata)})},${CSV_QUOTE(${CDR(start)})},${CSV_QUOTE(${CDR(answer)})},${CSV_QUOTE(${CDR(end)})},${CSV_QUOTE(${CDR(duration)})},${CSV_QUOTE(${CDR(billsec)})},${CSV_QUOTE(${CDR(disposition)})},${CSV_QUOTE(${CDR(amaflags)})},${CSV_QUOTE(${CDR(accountcode)})},${CSV_QUOTE(${CDR(uniqueid)})},${CSV_QUOTE(${CDR(userfield)})},${CDR(sequence)}
|
||||||
;Simple.csv => ${CSV_QUOTE(${EPOCH})},${CSV_QUOTE(${CDR(src)})},${CSV_QUOTE(${CDR(dst)})}
|
;Simple.csv => ${CSV_QUOTE(${EPOCH})},${CSV_QUOTE(${CDR(src)})},${CSV_QUOTE(${CDR(dst)})}
|
||||||
|
|
||||||
|
@@ -99,6 +99,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||||||
<enum name="channel">
|
<enum name="channel">
|
||||||
<para>Channel name.</para>
|
<para>Channel name.</para>
|
||||||
</enum>
|
</enum>
|
||||||
|
<enum name="sequence">
|
||||||
|
<para>CDR sequence number.</param>
|
||||||
|
</enum>
|
||||||
</enumlist>
|
</enumlist>
|
||||||
</parameter>
|
</parameter>
|
||||||
<parameter name="options" required="false">
|
<parameter name="options" required="false">
|
||||||
|
@@ -110,6 +110,8 @@ struct ast_cdr {
|
|||||||
char linkedid[32];
|
char linkedid[32];
|
||||||
/*! User field */
|
/*! User field */
|
||||||
char userfield[AST_MAX_USER_FIELD];
|
char userfield[AST_MAX_USER_FIELD];
|
||||||
|
/*! Sequence field */
|
||||||
|
int sequence;
|
||||||
|
|
||||||
/*! A linked list for variables */
|
/*! A linked list for variables */
|
||||||
struct varshead varshead;
|
struct varshead varshead;
|
||||||
@@ -143,9 +145,37 @@ int check_cdr_enabled(void);
|
|||||||
struct ast_cdr *ast_cdr_alloc(void);
|
struct ast_cdr *ast_cdr_alloc(void);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Duplicate a record
|
* \brief Duplicate a record and increment the sequence number.
|
||||||
|
* \param cdr the record to duplicate
|
||||||
* \retval a malloc'd ast_cdr structure,
|
* \retval a malloc'd ast_cdr structure,
|
||||||
* \retval NULL on error (malloc failure)
|
* \retval NULL on error (malloc failure)
|
||||||
|
* \see ast_cdr_dup()
|
||||||
|
* \see ast_cdr_dup_unique_swap()
|
||||||
|
*/
|
||||||
|
struct ast_cdr *ast_cdr_dup_unique(struct ast_cdr *cdr);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Duplicate a record and increment the sequence number of the old
|
||||||
|
* record.
|
||||||
|
* \param cdr the record to duplicate
|
||||||
|
* \retval a malloc'd ast_cdr structure,
|
||||||
|
* \retval NULL on error (malloc failure)
|
||||||
|
* \note This version increments the original CDR's sequence number rather than
|
||||||
|
* the duplicate's sequence number. The effect is as if the original CDR's
|
||||||
|
* sequence number was swapped with the duplicate's sequence number.
|
||||||
|
*
|
||||||
|
* \see ast_cdr_dup()
|
||||||
|
* \see ast_cdr_dup_unique()
|
||||||
|
*/
|
||||||
|
struct ast_cdr *ast_cdr_dup_unique_swap(struct ast_cdr *cdr);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Duplicate a record
|
||||||
|
* \param cdr the record to duplicate
|
||||||
|
* \retval a malloc'd ast_cdr structure,
|
||||||
|
* \retval NULL on error (malloc failure)
|
||||||
|
* \see ast_cdr_dup_unique()
|
||||||
|
* \see ast_cdr_dup_unique_swap()
|
||||||
*/
|
*/
|
||||||
struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr);
|
struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr);
|
||||||
|
|
||||||
|
37
main/cdr.c
37
main/cdr.c
@@ -74,6 +74,11 @@ static struct ast_cdr_batch {
|
|||||||
struct ast_cdr_batch_item *tail;
|
struct ast_cdr_batch_item *tail;
|
||||||
} *batch = NULL;
|
} *batch = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
static int cdr_sequence = 0;
|
||||||
|
|
||||||
|
static int cdr_seq_inc(struct ast_cdr *cdr);
|
||||||
|
|
||||||
static struct sched_context *sched;
|
static struct sched_context *sched;
|
||||||
static int cdr_sched = -1;
|
static int cdr_sched = -1;
|
||||||
static pthread_t cdr_thread = AST_PTHREADT_NULL;
|
static pthread_t cdr_thread = AST_PTHREADT_NULL;
|
||||||
@@ -165,6 +170,26 @@ int ast_cdr_isset_unanswered(void)
|
|||||||
return unanswered;
|
return unanswered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ast_cdr *ast_cdr_dup_unique(struct ast_cdr *cdr)
|
||||||
|
{
|
||||||
|
struct ast_cdr *newcdr = ast_cdr_dup(cdr);
|
||||||
|
if (!newcdr)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cdr_seq_inc(newcdr);
|
||||||
|
return newcdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ast_cdr *ast_cdr_dup_unique_swap(struct ast_cdr *cdr)
|
||||||
|
{
|
||||||
|
struct ast_cdr *newcdr = ast_cdr_dup(cdr);
|
||||||
|
if (!newcdr)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cdr_seq_inc(cdr);
|
||||||
|
return newcdr;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Duplicate a CDR record
|
/*! Duplicate a CDR record
|
||||||
\returns Pointer to new CDR record
|
\returns Pointer to new CDR record
|
||||||
*/
|
*/
|
||||||
@@ -279,6 +304,8 @@ void ast_cdr_getvar(struct ast_cdr *cdr, const char *name, char **ret, char *wor
|
|||||||
ast_copy_string(workspace, cdr->linkedid, workspacelen);
|
ast_copy_string(workspace, cdr->linkedid, workspacelen);
|
||||||
else if (!strcasecmp(name, "userfield"))
|
else if (!strcasecmp(name, "userfield"))
|
||||||
ast_copy_string(workspace, cdr->userfield, workspacelen);
|
ast_copy_string(workspace, cdr->userfield, workspacelen);
|
||||||
|
else if (!strcasecmp(name, "sequence"))
|
||||||
|
snprintf(workspace, workspacelen, "%d", cdr->sequence);
|
||||||
else if ((varbuf = ast_cdr_getvar_internal(cdr, name, recur)))
|
else if ((varbuf = ast_cdr_getvar_internal(cdr, name, recur)))
|
||||||
ast_copy_string(workspace, varbuf, workspacelen);
|
ast_copy_string(workspace, varbuf, workspacelen);
|
||||||
else
|
else
|
||||||
@@ -292,7 +319,7 @@ void ast_cdr_getvar(struct ast_cdr *cdr, const char *name, char **ret, char *wor
|
|||||||
static const char * const cdr_readonly_vars[] = { "clid", "src", "dst", "dcontext", "channel", "dstchannel",
|
static const char * const cdr_readonly_vars[] = { "clid", "src", "dst", "dcontext", "channel", "dstchannel",
|
||||||
"lastapp", "lastdata", "start", "answer", "end", "duration",
|
"lastapp", "lastdata", "start", "answer", "end", "duration",
|
||||||
"billsec", "disposition", "amaflags", "accountcode", "uniqueid", "linkedid",
|
"billsec", "disposition", "amaflags", "accountcode", "uniqueid", "linkedid",
|
||||||
"userfield", NULL };
|
"userfield", "sequence", NULL };
|
||||||
/*! Set a CDR channel variable
|
/*! Set a CDR channel variable
|
||||||
\note You can't set the CDR variables that belong to the actual CDR record, like "billsec".
|
\note You can't set the CDR variables that belong to the actual CDR record, like "billsec".
|
||||||
*/
|
*/
|
||||||
@@ -847,6 +874,11 @@ int ast_cdr_setcid(struct ast_cdr *cdr, struct ast_channel *c)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cdr_seq_inc(struct ast_cdr *cdr)
|
||||||
|
{
|
||||||
|
return (cdr->sequence = ast_atomic_fetchadd_int(&cdr_sequence, +1));
|
||||||
|
}
|
||||||
|
|
||||||
int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *c)
|
int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *c)
|
||||||
{
|
{
|
||||||
char *chan;
|
char *chan;
|
||||||
@@ -856,6 +888,7 @@ int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *c)
|
|||||||
chan = S_OR(cdr->channel, "<unknown>");
|
chan = S_OR(cdr->channel, "<unknown>");
|
||||||
ast_copy_string(cdr->channel, c->name, sizeof(cdr->channel));
|
ast_copy_string(cdr->channel, c->name, sizeof(cdr->channel));
|
||||||
set_one_cid(cdr, c);
|
set_one_cid(cdr, c);
|
||||||
|
cdr_seq_inc(cdr);
|
||||||
|
|
||||||
cdr->disposition = (c->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NOANSWER;
|
cdr->disposition = (c->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NOANSWER;
|
||||||
cdr->amaflags = c->amaflags ? c->amaflags : ast_default_amaflags;
|
cdr->amaflags = c->amaflags ? c->amaflags : ast_default_amaflags;
|
||||||
@@ -1116,7 +1149,7 @@ void ast_cdr_reset(struct ast_cdr *cdr, struct ast_flags *_flags)
|
|||||||
if (ast_test_flag(&flags, AST_CDR_FLAG_LOCKED) || !ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
|
if (ast_test_flag(&flags, AST_CDR_FLAG_LOCKED) || !ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
|
||||||
if (ast_test_flag(&flags, AST_CDR_FLAG_POSTED)) {
|
if (ast_test_flag(&flags, AST_CDR_FLAG_POSTED)) {
|
||||||
ast_cdr_end(cdr);
|
ast_cdr_end(cdr);
|
||||||
if ((duplicate = ast_cdr_dup(cdr))) {
|
if ((duplicate = ast_cdr_dup_unique_swap(cdr))) {
|
||||||
ast_cdr_detach(duplicate);
|
ast_cdr_detach(duplicate);
|
||||||
}
|
}
|
||||||
ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
|
ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
|
||||||
|
@@ -2804,7 +2804,7 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
|
|||||||
if (chan_cdr) {
|
if (chan_cdr) {
|
||||||
ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
|
ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
|
||||||
ast_cdr_update(chan);
|
ast_cdr_update(chan);
|
||||||
bridge_cdr = ast_cdr_dup(chan_cdr);
|
bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr);
|
||||||
ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
|
ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
|
||||||
ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
|
ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
|
||||||
} else {
|
} else {
|
||||||
|
Reference in New Issue
Block a user