[Home]

Summary:ASTERISK-11309: Missing CDR's for Transfers
Reporter:Grey VoIP (greyvoip)Labels:
Date Opened:2008-01-26 11:11:12.000-0600Date Closed:2009-10-01 14:48:02
Priority:MajorRegression?No
Status:Closed/CompleteComponents:CDR/General
Versions:Frequency of
Occurrence
Related
Issues:
Environment:Attachments:( 0) 11849.bxfer.patch
( 1) attendedtransfer.agi
( 2) cdr_transfer_function.patch
( 3) settransferfield.agi
( 4) v2-attendedtransfer.agi
( 5) v2-blindtransfer.agi
( 6) v2-settransferfield.agi
( 7) v2-setuniqueid.agi
Description:At the moment there is one CDR generated per generic bridge. This tends not to create any problems when the bridge has been created by something like:

SIP User -> Asterisk -> PSTN

The CDR generated will have the PSTN number as the destination and the SIP User's accountcode.

When a transfer is undertaken the one CDR per generic bridge approach breaks down. An example call flow for a blind transfer is:

SIP User -> Asterisk -> PSTN
PSTN <- Asterisk -> PSTN (this is after the user has blind transferred the first call to a second PSTN number)

At the moment Asterisk will correctly generate a CDR for the first call leg but for the second call leg there is a problem. For the sconed call leg both ends of the bridge are now billable but as Asterisk only generates a single CDR per bridge one of the legs will not get billed.

A straight forward fix (at least architecturally) would be to generate a CDR for each end of the bridge instead of combining both ends into a single CDR. It would mean some extra CDR's for the standard SIP User -> PSTN call but it's a lot easier to filter out CDR's to ignore than it is to try and work out how to handle ones that are missing.

I've classified this as major since it's costing me (and other providers) money every time a user does a transfer :).
Comments:By: Tilghman Lesher (tilghman) 2008-01-26 19:09:00.000-0600

Please read 'core show application ForkCDR'

By: Grey VoIP (greyvoip) 2008-01-26 20:45:44.000-0600

ForkCDR is no good and in fact Olle had already suggested that as an approach. It's no good having two CDR's with the same data differing just in the times.

Fair enough if the issue should be closed as a bug since it's more a design decision but there are a number of us having issues with transfer CDR's and those of us that run Asterisk in a provider environment have to either take the hit on losing money due to the missing CDR or have to put in mechanisms to prevent the transfers taking place.

See other similar bugs raised on this issue:
http://bugs.digium.com/view.php?id=11093
http://bugs.digium.com/view.php?id=8221

By: Tilghman Lesher (tilghman) 2008-01-26 21:12:51.000-0600

I think you would be wise to reconsider ForkCDR, along with cdr_adaptive_odbc or cdr_addon_mysql (both in trunk), as those modules will let you define arbitrary CDR columns that can be used for whatever purpose you like.  cdr_pgsql is also getting those capabilities, in bug ASTERISK-9010.

See http://svncommunity.digium.com/view/tilghman/branches/1.4/ for a backport of cdr_adaptive_odbc to 1.4.

By: Grey VoIP (greyvoip) 2008-01-26 23:57:01.000-0600

With blind transfers ForkCDR could be an option if called in the TRANSFER_CONTEXT although it still looks quite difficult. The CDR I get when using a ForkCDR with that approach lack the destination and don't have any billing or answer times.

With attended transfers I can't see any way to use ForkCDR as the transfer operation is bridging two existing calls and does not appear to go into the dialplan again and therefore does not provide anywhere for ForkCDR to be called.

Even if there was a way to do attended transfers with some sort of TRANSFER_CONTEXT and ForkCDR mechanism it's pretty tricky stuff. I have been looking at this on and off for a year now and the solution I use is to block REFER requests on the SIP Proxy where the transfer destination is not a free call. For other providers or people new to Asterisk the default transfer CDR's leave them in a very dangerous situation. For instance with 1.4 at the moment the destination reported after an attended transfer is "s". So if I place a call to one mobile number and then a second call to another mobile number and transfer them together I will only be billed for the time it takes me to get the transfer done.

I've verified that it's not only my set up that's affected. I signned up with some other known Asterisk based providers to check what I got billed for when doing a trnasfer and in cases where the trnasfer did get through the billing was incorrect. I kept the calls short of course :).

Incidentally murf has had a crack at improving the CDR handling, although I think that has now stalled a bit, at least from what I can gather from the last emails I saw on the Asterisk User's list. At the bottom of his blog post he expresses a view on ForkCDR.

http://www.asterisk.org/node/48358

At least now in 1.4 there is the option to turn trnasfers off but I do believe the CDR's currently being produced for blind and attended transfers are dangerously incorrect.

By: C F (shmaltz) 2008-01-29 14:08:06.000-0600

I have already said this on the list but I'm repeating here for reference.
ONLY TESTED ON 1.2.x and only with SIP BLIND XFER.
the lastdata field has the right number. When doing rating one should match that to the dst field and based on that figure out it was an xfer, and charge based on lastdata field.
At least in Asterisk 1.2 it always creates 2 records and the lastdata field has the right number.

By: Grey VoIP (greyvoip) 2008-01-29 14:32:30.000-0600

There's no way you could tell from the lastdata field on a blind transfer CDR whether the call was part of a transfer or not. Perhaps you could do something tricky by dropping the call into the TRANSFER_CONTEXT and recording the first call leg destination in the CDRUserField. It's a bit of a hack though and will only work for blind transfers. For attended transfers you can't use that approach.

Aside from that it's not so much the there may be a work around for this case and that case the point is the CDR's being generated are incorrect. Isn't the best idea to correct them?

By: C F (shmaltz) 2008-01-29 16:48:32.000-0600

Based on my tests there is (unless it's transfered to the same number) since the lastdata will not be the same as dst in a transfer. While I agree it's not what you were looking for, it could be the only way for you to bill accurately.

By: jmls (jmls) 2008-02-17 13:07:13.000-0600

greyvoip, any further comments ?

By: Ross Beer (rossbeer) 2008-02-21 04:05:45.000-0600

I to am having this same problem, See ticket http://bugs.digium.com/view.php?id=11093

I think the CDR billsec should continue to increase, however they stop, though they are only written to the database once the entire call ends.

By: Grey VoIP (greyvoip) 2008-02-22 19:19:58.000-0600

My humble opinion would be that using the lastdata cdr field or any other "trick" to correctly bill a call is very fragile not to mention pretty tough for anyone new to Asterisk and billing engines to sort out.

I didn't see the extra notes added to this ticket but since my original bug post I did try and get some discussion going on the User's list about a new design for the CDR mechanism but unfortunately didn't get very far :).

http://lists.digium.com/pipermail/asterisk-users/2008-January/204856.html

My opinion (again humble) is that CDR's should be genereated for each end of a bridge. The current approach of generating a single CDR for each bridged call will always struggle to cope when blind and attended transfers are concerned.

A CDR per call leg is a lot cleaner and even simpler and it's a lot easier for people to filter out unwanted CDRs than it is to try and "manufacture" them out of say a lastdata field.



By: Jeff Pyle (jpyle) 2008-04-16 09:13:10

I just discovered this problem on 1.2.26 after an attended transfer generated only one CDR.  It shows up as though the first called party placed a call to the second called party using a "channel" available only to the caller of both calls.  Yes, this will definitely do nasty things to billing.

By: Digium Subversion (svnbot) 2008-07-02 19:09:12

Repository: asterisk
Revision: 127663

U   branches/1.4/channels/chan_dahdi.c
U   branches/1.4/channels/chan_sip.c
U   branches/1.4/include/asterisk/cdr.h
U   branches/1.4/main/cdr.c
U   branches/1.4/main/channel.c
U   branches/1.4/main/pbx.c
U   branches/1.4/res/res_features.c

------------------------------------------------------------------------
r127663 | murf | 2008-07-02 19:08:58 -0500 (Wed, 02 Jul 2008) | 30 lines

The CDRfix4/5/6 omnibus cdr fixes.

(closes issue ASTERISK-10481)
Reported by: murf
Tested by: murf, deeperror

(closes issue ASTERISK-12240)
Reported by: falves11
Tested by: murf, falves11


(closes issue ASTERISK-11309)
Reported by: greyvoip

As to 11849, I think these changes fix the core problems
brought up in that bug, but perhaps not the more global
problems created by the limitations of CDR's themselves
not being oriented around transfers.

Reopen if necc, but bug reports are not the best
medium for enhancement discussions. We need to start
a second-generation CDR standardization effort to cover
transfers.

(closes issue ASTERISK-10625)
Reported by: rossbeer
Tested by: greyvoip, murf



------------------------------------------------------------------------

http://svn.digium.com/view/asterisk?view=rev&revision=127663

By: Grey VoIP (greyvoip) 2008-07-09 07:06:10

I don't think this bug should be closed until CDRs for the two very specific cases of blind and attended transfers are reported correctly. Closing the bug while they are still not correct will give readers the impression the bug is fixed rather than improved.

Currently the CDRs are correct for attended transfers, which is a big improvement and thanks go to murf for all his efforts. However for blind transfers the CDRs are incorrect which leaves it possible for Asterisk based providers relying on its CDRs to be exploited.

As an example a user can call an expensive destination and then blind transferring to a free destination, such as their own extension, and they will only billed for the expensive destination up until the time of the blind transfer.


By: Steve Murphy (murf) 2008-07-10 08:35:00

Just so everyone can see the conversation about this bug, I'm
taking the liberty of pasting in the relevant contents of an
email from greyvoip:

Your blind transfer scenario above is the one that's handled
correctly. The reason it's ok is that A stays on the call and we're
not concerned about billing received call legs.

The scenario that doesn't get recorded correctly is:

1. A calls B.
2. A blind xfers B to C.
3. B and C converse...
4. Call ends.

There are two CDRs we need from this call.

1. CDR for call to B of duration 1 to 4,
2. CDR for call to C from 2 to 4.

The problem is with CDR 1 its duration is from 1 to 2.

By: Steve Murphy (murf) 2008-07-30 09:28:46

OK, I'm back on this bug. I've looked at the situation, and yes,
I've verified that the second CDR has the same start time as the first,
when it **SHOULD** have the end time of the first. But it's going
to be tricky, finding where in the code would be the best place to
make a tweak.

In the meantime, I also note a discrepancy in the src and channel fields
in the 2nd CDR. And also, a bit of a logical inconsistency in the src/channel
data in general: Party A made the call to C--- B and C use the connection
to talk. Isn't recording that C made the call in the 2nd CDR wrong? But if
I change this, then I'm sure some folks will be messed over. Right now,
the src says A, the channel says C, and dstchannel is B.


By: Digium Subversion (svnbot) 2008-07-31 14:15:24

Repository: asterisk
Revision: 134883

U   branches/1.4/res/res_features.c

------------------------------------------------------------------------
r134883 | murf | 2008-07-31 14:15:24 -0500 (Thu, 31 Jul 2008) | 51 lines

(closes issue ASTERISK-11309)
Reported by: greyvoip
Tested by: murf

OK, a few days of debugging, a bunch of instrumentation
in chan_sip, main/channel.c, main/pbx.c, etc. and 5 solid
notebook pages of notes later, I  have made the small
tweek necc. to get the start time right on the second
CDR when:

 A Calls B
 B answ.
 A hits Xfer button on sip phone,
 A dials C and hits the OK button,
 A hangs up
 C answers ringing phone
 B and C converse
 B and/or C hangs up

But does not harm the scenario where:

 A Calls B
 B answ.
 B hits xfer button on sip phone,
 B dials C and hits the OK button,
 B hangs up
 C answers ringing phone
 A and C converse
 A and/or C hangs up

The difference in start times on the second CDR is because
of a Masquerade on the B channel when the xfer number is
sent. It ends up replacing the CDR on the B channel with
a duplicate, which ends up getting tossed out. We keep
a pointer to the first CDR, and update *that* after the
bridge closes. But, only if the CDR has changed.

I hope this change is specific enough not to muck
up any current CDR-based apps. In my defence, I
assert that the previous information was wrong,
and this change fixes it, and possibly other
similar scenarios.

I wonder if I should be doing the same thing
for the channel, as I did for the peer, but
I can't think of a scenario this might affect.
I leave it, then, as an exersize for the users,
to find the scenario where the chan's CDR
changes and loses the proper start time.


------------------------------------------------------------------------

http://svn.digium.com/view/asterisk?view=rev&revision=134883

By: Grey VoIP (greyvoip) 2008-10-26 09:13:47

I've just got around to testing the transfer CDRs in 1.4.22 and there is still a problem.

The problem below still occurs.

> The scenario that doesn't get recorded correctly is:
>
> 1. A calls B.
> 2. A blind xfers B to C.
> 3. B and C converse...
> 4. Call ends.
>
> There are two CDRs we need from this call.
>
> 1. CDR for call to B of duration 1 to 4,
> 2. CDR for call to C from 2 to 4.
>
> The problem is with CDR 1 its duration is from 1 to 2.

The situation for 1.4.22 and blind transfers is

(A is a local Asterisk SIP user (non-billable call), B and C are PSTN (billable calls)

1. A calls B and B answers,
2. A blind xfers B to C and C starts ringing,
3. C answers and B and C converse,
4. Call ends.

The CDRs generated by 1.4.22 are (same result as for 1.2):

1. B for 1 to 2,
2. C for 3 to 4.

The correct CDRs are:

1. B for 1 to 4,
2. C for 3 to 4.

-------------------

Attended transfers are also back to being incorrect although they have improved since earlier versions of 1.4.

The situation for 1.4.22 and attended transfers is:

(A is a local Asterisk SIP user (non-billable call), B and C are PSTN (billable calls)

1. A calls B and B answers,
2. A calls C and C answers,
3. A transfers B and C together,
4. Call ends.

The CDRs generated by 1.4.22 are:

1. B for 1 to 3,
2. C for 2 to 4.

The correct CDRs are:

1. B for 1 to 4,
2. C for 2 to 4.

The CDRs are likely to work out more expensive for providers than 1.2, although once users work out the flaw it's easily exploited, which produced:

1. B for 1 to 4,
2. B for 2 to 4 (B is not a typo).


By: Grey VoIP (greyvoip) 2008-10-27 03:32:28

I just tested the transfer CDRs on 1.6.0.1. The CDRs for Blind Transfers are incorrect in the same fashion as 1.4.22. The CDRs for Attended Transfers with 1.6.0.1 are correct! At least for my specific test case.

By: mdu113 (mdu113) 2008-10-28 17:10:03

Don't know if it's helpful, but my production system are running SVN-branch-1.4-r118858 and that revision produces correct cdrs for the following blind transfer scenario: A calls B, B xfers call to C. It's correct according to greyvoip's definition above, which I agree with. The scenario when A calls B and then A xfers to C is still incorrect.

By: Grey VoIP (greyvoip) 2008-10-29 07:52:46

I checked out the latest 1.4 version from trunk, SVN-trunk-r152605, and the blind transfer CDR is incorrect in the same way as 1.4.22, i.e.:

(A is a local Asterisk SIP user (non-billable call), B and C are PSTN (billable calls)

1. A calls B and B answers,
2. A blind xfers B to C and C starts ringing,
3. C answers and B and C converse,
4. Call ends.

The CDRs generated are (same result as for 1.2 and 1.4.22):

1. B for 1 to 2,
2. C for 3 to 4.

-----------------------------------

I also checked out SVN-branch-1.4-r118858. For the blind transfer scenario above the CDR results were:

1. B for 1 to 2,
2. C for 1 to 4.

This is different from any other version I've seen but is still not correct. It did make me go back and check whether I had possibly misread the call timings on 1.4.22 and/or 1.4 Trunk for the blind transfer CDRs but I hadn't.

The CDRs should be:

1. B for 1 to 4,
2. C for 3 to 4.

In the case of SVN-branch-1.4-r118858 the first call leg (to B) will be undercharged and the second call leg (to C) will be overcharged. From a provider's point of view it's a philosophical question as to whether that's better or worse than 1.4.22 where B is undercharged and C is correct.

Attended transfer CDRs were correct for SVN-branch-1.4-r11885.



By: Steve Murphy (murf) 2008-10-29 09:08:14

There are at least two issues here:

1. Blind xfer, case where A calls B, A transfers B to C... you want CDR 1 to
reflect from events 1 to 4, but it currently only reflects from 1 to 2.

2. Attended xfer, CDR 2 reflects call from B rather than C.

I think I can comment right now on issue #1; I've discussed this
problem before, somewhere, sometime. I know other people would like
CDR #1 to reflect the answer->end time from events 1 to 4, but in the
current system, it's just plain impossible. I've been willing to do a lot
of work (and intro a lot of regressions, etc) to fix CDR's, but this one
would require a re-engineering of the way CDR's are gathered and tracked.

The problem is this: CDR's are stored on the channel.  When the channel
is terminated, the CDR stored on it is either posted or discarded. In this
particular scenario, when A blind transfers B to C, A will get congestion,
and has to hang up (depending on the channel type). A's channel is gone.
He could open a new channel and make 20 calls before B and C are finished
conversing. There is no way or "where" to keep that CDR alive until event #4.

While re-engineering the CDR system sounds like a wild and impossible
idea, actually, it is well underway. The underpinning is the CEL work
(see the team/group/newcdr). In that branch, I have a direct CEL->db
backend, which I will throw away. Single event databases are useless;
Brian Degenhardt has shown that.

Instead, the critical piece that needs
to be written is a converter from CEL events to CDR records. Right now,
it lives only my imagination, but perhaps I might find time to work on it
after the beginning of 2009. Such a project would allow us to step above
the channel/CDR association, and give us more control over what events
the end-user wants to see in the reports.

Also, the CDR records themselves, as they now stand, are insufficient.
We have src and destination, but this isn't enough, we need originator,
and party A and B. Originator is the guy who dialed the call, and is
probably the guy you want to bill. Party A and Party B are the two guys/gals
who talked on that connection. In the simple "A calls B" path, I guess
A would be both originator and party A. But for transfers, A would originate,
and B and C would be the two parties.

CEL introduces a new field, "linkedID", which is "viral", and is copied to the newer channel whenever two channels are linked in some way. It can be used to link all the legs of a complex xfer sequence, like when A calls B, tranfers B to C, C transfers B to D, B transfers D to E, E transfers D to ... you get the idea. Anyway, 'linkedID' can be used to tie all such legs into a single call,
and issue 'summary' CDR records, if that's what's needed.

CDR records don't have a "type". For instance, there's no way to tell if/when there was a 3 way conversation; no way to see parking times, hold times, etc. We could optionally produce special records that can help identify these situations.

Using SQL queries from simple to complex, users could generate reports on all sorts of interesting things, like average park and hold times, etc.

OK, I've spouted off long enough on issue #1.
I'll investigate #2, which looks like reassignment of the source to the dialing party. Again, because of the insufficiency of the current CDR records, you'll lose the info that one of the parties was involved in the call... but hey, who cares, as long as the right guy gets billed for it, eh?

By: mdu113 (mdu113) 2008-10-29 16:41:00

I've got an idea that I want to share and discuss with you. First of all, I do agree that actually fixing the cdrs is the best thing to do, but if that's too hard and involves some complex design decisions, may be we can use the following workaround.
I think blindly transferred calls can be billed properly with no changes to asterisk exploiting the inheritable channel variables and cdr userfield.
The dialplan logic would be something like follows:

if BLINDTRANSFER is set {
  Set(CDR(userfield)=${XFERRER}
}
Set(__XFERRER=${UNIQUEID})

i.e. we set XFERRER variable to channel uniqueid for every call and in case of blind transfer it will be inherited and available in the new call. By putting it into userfield we can now correlate to cdrs generated and calculate the correct billing time. Now, for our favorite example:
1. A calls B. Talks to B for 10 seconds
2. A blindly transfers B to C
3. C answers and they talk for 60 seconds
4. call ends
we have the following 2 cdrs:
  Start time    Uniqueid    Billsec    Userfield
1. 00:00         01          10
2. 00:15         02          60         01
Now this 2 cdrs can be correlated as 2nd being a transfer of 1st and so correct billing time can be calculated for the 1st cdr as
billsec_1=(start_time_2 - start_time_1)+billsec_2
As far as I can tell (and according to my testing) it's going to work for any blind transfer scenario.
I think something like that can also be used for attended transfers with some help from asterisk. If transfer handling code, where all information is available, could set some channel variable for the transferred call that would contain an id of the transferror, then in the 'h' extension we could catch that value and put it in userfield, thus making it possible to correlate 2 generated cdrs to each other and so calculate the correct billing time.
What do you think?

By: Grey VoIP (greyvoip) 2008-10-30 06:05:24

mdu113 in answer to your question it's already possible to "hack" together a CDR for a Blind Transfer by making use of the fact that when the Transfer occurs it goes through the TRANSFER_CONTEXT (I've probably got that name wrong). Doing this adds extra complexity to your dialplan and billing logic but it can be done and I'd say that's less of an effort then a code change for a quick fix.

murf it would be extremely disingenuous for me to criticise your efforts since you are the only core developer to take an interest in this very "un-sexy" area. I for one and am very appreciative of your efforts and any criticisms I might make are definitely not directed towards you personally.

What frustrates me with regards to this bug is that I can't understand why it's not given a very high priority. As I've said a few times this is costing providers money. And I'm not just saying that, I have literally placed calls with public ITSP's and obtained free call legs (of course I kept the legs brief as I'm not out to cost anybody anything). I contacted those ITSP's and one denied he had the problem, despite the fact that I had placed the free call and another one was very worried but not enough so to jump on this bug report and help me agitate ;-).

Despite all the comments to the contrary the fix for this problem is conceptually simple. The Asterisk designers have incorrectly created a 1-to-1 relationship between CDRs and bridges. There is no way that is ever going to work in complicated call scenarios and in fact as we see here it's not even working for next to the simplest ones! The fix is to break the 1-to-1 relationship between bridges and CDRs and instead make it 1-to-1 between channels and CDRs. Conceptually it's that easy and I can vouch for it working in other softswitches.

I should take the time to look at doing a fix for this myself but what puts me off is the fact that unless there is agreement on the design with the powers that be (aka Russell and/or Kevin) in the first place any patch by a non-core developer is not going to make it anywhere near Asterisk when it's so close to the bone!

As for CEL and the new CDR approach I've mentioned before that it scares me a lot. Again I'm not trying to criticise for the sake of it and CEL sounds like it's going to be good for some things but retrofitting it for CDR's looks to me like a sledge hammer for a thumb tack solution.

And while I'm ranting away I would also argue that at the very least this bug should not be closed while the solution is not fixed regardless of whether it's too hard or not. Closing the bug will give people the false impression it's been fixed.

By: David Woolley (davidw) 2008-10-30 06:46:06

Something I find slightly strange is that the code does seem to record CDRs against channels, but then goes and copies the CDR for the bridge and sets flags on the other copies to inhibit their output.  It is all making it very difficult for me to get a good conceptual model of how CDRs work, especially as it also interacts with masquerading, another conceptually difficult area.

By: mdu113 (mdu113) 2008-10-30 10:01:44

greyvoip, as far as I know TRANSFER_CONTEXT is only applicable for pbx DTMF transfers and doesn't work for SIP transfers (at least I couldn't make it working with SIP transfers).
Unlike you, I haven't seen how it works in other softswitches, but I imagine that having a cdr per channel would pose a problem of identifying which cdr belongs to which call and that's probably not going to be simple as well.
Having said that, I would vote for any solution that would allow me to do proper call accounting even if it means to redo my billing system and if everybody agrees that cdr per channel is a way to go, so be it. It just doesn't look like it's going to happen any time soon.
So my suggestion is this. If it's so hard to get cdr stuff in asterisk right for historical/technical/political/whatever reason then we could use the minimally intrusive approach I mentioned above. Seriously what would you prefer, waiting who knows how long for the proper solution or start billing now?

By: Steve Murphy (murf) 2008-10-30 12:02:22

mdu113 -- I like your idea about providing a dialplan workaround;
There are at least two ways to do a blind transfer/attended transfer--
one via the 'features' machanism; and the other built into the channel
driver (chan_sip in your case, I guess).

I see that the blindtransfer routines in both features.c and chan_sip.c set the channel variable "BLINDTRANSFER" on both the referer and refer-ee, with the name of the opposing channel. I do not see this machinery in the atxfer code, tho, in either place...

Would it help if I added BLINDTRANSFER_UNIQUEID, that contains the uniqueid setting of the opposing channel?  (You guys will love the linkedid coming up in trunk someday.(soon, I hope))

I traced the code in the attended xfer in features.c (res_features.c in 1.4), and understand the flow, but there at least 4 separate failure exits from the process, and how/if to set an ATTENDEDTRANSFER variable (if we decide that's best) is problematic. Maybe we just set the BLINDTRANSFER var(s) on attended transfers, too, then, and avoid the hassle of having two vars to check. We could set it in the new channel and refer-ee channels just before the final bridge between the two....

What to do when the attended transfer is initiated, but the number wrong, the called party doesn't answer, the referred party hangs up in the middle of the process, etc. need to be decided...


Also, most sip phones provide the hold/conference buttons/facilities, where the phone itself bridges the two channels to make a 3-way...

Greyvoip -- As to bridge-based vs channel based, it *was* channel based, (really, it still basically is) and I shifted to bridge-based to solve definite problems with legs not getting reported in xfers. The code is very "folded"-- maximizing the sharing of code and minimizing code redundancy, which is good, very good, but makes it a nightmare to isolate particular circumstances where you need to do "this" instead of the normal "that"... another factor that complicates things is that the CDR gathers 3 events and contains copies of channel fields, creating confusion about when updates occur, if at all, if channel fields are changed.

davidw -- don't get discouraged. Getting your brain wrapped around all the ramifications of the CDR code is not a 10-minute process, at least it isn't for me. If you feel you've reached nirvana and understand it all, we need to talk!



By: mdu113 (mdu113) 2008-10-30 12:56:24

murf, my opinion is this.
1. BLINDTRANSFER_UNIQUEID - will help by simplifying dialplan a little, but this is optional as the same effect can be achieved in dialplan.
2. I'm for using separate ATXFER variable, because ATXFER and BLINDTRANSFER actually represent different events with probably different reaction, ATXFER will be available only in 'h' extension, while BLINDTRANSFER is available all the time, because blindly transferred call could be atxferred later
3. If transfer actually doesn't complete, I wouldn't bother to do anything specific as in most cases not completed calls are not billable but I guess trying to cover all those situations can complicate things a lot.

By: mdu113 (mdu113) 2008-10-30 13:01:21

The most important things about it is actually to be sure that whatever rules will be defined are going to be stable.
If we go that way it will require some significant change in my billing system, which I'm willing to do, but I'd really like to be sure that these rules aren't going to change in a few weeks.

By: frawd (frawd) 2008-10-30 15:22:37

Hello all,

Just to get this clear: I understand this looks like very important *security* issue (correct me if I'm wrong).

Shouldn't there be an official advisory telling providers to disable transfers, or are there any existing workarounds (however complicated they might be) in order to have correct billing with existing CDRs (in 1.4.22) for any kind of transfer situation (attended, blind, from dtmf features, from chan_sip, ...)?

Thanks for the work on trying to resolve this anyway, it looks kind of complicated!

Offtopic: Anyone knows if callweaver, freeswitch or other open source solutions also suffer from CDR problems?

By: Grey VoIP (greyvoip) 2008-10-31 01:16:57

Hi frawd,

Well it's been a very important issue for me for a long time but everyone else I have spoken to about it seems to be something they can live with although it beats me how when it's costing a lot of them money...

I did make a serious attmept to raise awareness of the issue on the mailing list but didn't really get too much interest http://lists.digium.com/pipermail/asterisk-users/2008-January/204856.html.

FreeSwitch has the same problem if you use the CDR engine that was derived from the ASterisk fork but apparently it works properly if the the XML CDR module is used but I am yet to verify that.

By: Grey VoIP (greyvoip) 2008-10-31 01:28:55

mdu113 the accountcode is what gets used to associate a channel to a user and it's completely simple and unambiguous to associate a channel with a user whereas associating a bridge to a user, which is the current situation, is not. With a bridge which end "owns" the call. Obviously we have all worked out how to cope with it for standard incoming and outgoing calls but above that and as we're seeing here it gets messy. I've confined my transfer scenarios to two specific cases but if you look at a blog post murf did a while ago your head will end up spinning with all the scenarios.

murf when I say a CDR per channel I have probably confused things slightly. I'm not so much referring to the SIP or IAX channel but to one CDR per ast_channel struct. At the moment each ast_channel does seem to maintain it's own CDR structure up till a point but then when bridged use bits and pieces from the two channels are combined or one overwrites the other. If they were kept separate and each generated a CDR it would completely solve the problem.

I think it is now possible to put a workaround in for the tarbsfer CDRs in 1.6.0.1 using the dialplan. Blind transfers are currently the broken ones and they do go back to the dialplan when the transfer occurs so forkcdr and a bit of mangling could be used. Previously it was attended transfers that nothing could be done about but now they are actually correct in 1.6.0.1 so that's something.

By: mdu113 (mdu113) 2008-10-31 09:48:58

greyvoip, I have no problems associating cdr to a user. In case of transfer I have the problem of identifying 2 produced cdrs as related to each other, 'cause that could be used for calculating the correct billing time.
Sure it's better if asterisk could produce the correct cdrs right away and if you say 1.6.0.1 are producing ones that's really something.
murf, is it possible to backport those changes to 1.4?

By: Steve Murphy (murf) 2008-10-31 11:09:35

Well, I hate to say this, but 1.6.0 is a queer beast. It got frozen for all but the most serious bug fixes, and I *think* it has several bug fixes made to 1.4 and trunk and 1.6.1 all excluded. So anything you really like about it will most certainly go away in 1.6.1, and we just plain need to fix it in the current stuff. Sorry. 1.4 and trunk and 1.6.1 are all pretty much identical when it comes to CDR's. (Thank goodness, because keeping up two versions of this stuff would be very tiring).

I'll try to see what the problem is with AT's and get that back to normal/correct if I can; and we can try to figure out how to put the BLINDTRANSFER stuff into the ATXFER code.



By: Steve Murphy (murf) 2008-10-31 12:10:59

frawd--

I remember asking about this of thing maybe two years ago, if this sort of thing might classify as a security problem. IIRC, all I got was blank stares. (Reminds me of deer in headlights). It's kinda in the gray zone... Such problems don't allow remote execution, but might allow some unwary ISPs/etc, to allow some free calls, if they haven't overcome the problem in the dialplan (like mdu113 is doing/planning), or by using forkCDR/ResetCDR tricks, etc, or just tossing the whole affair and doing their own thing with custom backends/etc.

I try to fix things quickly whenever this sort of thing arises, either way.

By: Steve Murphy (murf) 2008-10-31 14:00:22

I've just attached a patch to set BLINDTRANSFER in attended transfer scenarios, in a manner similar to blind transfers; please test this; there is a chance that I miscalculated, and have the wrong channels marked. I did chan_sip, chan_dahdi,
chan_misdn, chan_mgcp, and of course res_features for that attended xfer, if activated.

By: Steve Murphy (murf) 2008-11-01 10:07:37

OK, for attended xfers, I've looked at the results of both

A calls B (sip) [1], B answers [2],  B puts A on hold, B dials C [4], C answers [5], B & C talk; B hits the xfer button [3], A &  C are connected; A&C hangup [6].

and

A(sip) calls B [1], B answers [2],  A puts B on hold, A dials C [4], C answers [5], A & C talk; A hits the xfer button [3], B &  C are connected; B&C hangup [6].

The numbers in square brackets are the start, answer, and end times of each of the two cdrs, in that order, where 1-3 is the first cdr, and 4-6 is the second.

So, yes, the first cdr ends at your time (3), when the transferer basically hits the xfer button and ends the conversation, which directly mirrors the blind transfer case, and for the same reasons -- when the guy making the call hangs up (or is hung up), the channel ends, and the CDR is posted.  

THe only thing I could think of, that might give the effect you seek, is to pull the CDR off the transferer, and stick it on the transferee, like a fork. But that leads to all sorts of interesting complications; I'll think about it.

In the meantime, treating atxfers like blindxfers with the before-mentioned patch is an alternative...

By: frawd (frawd) 2008-11-01 12:23:49

Re-reading this bug's history, I think the best (and maybe simplest) way to make transfer times in CDRs work in all situations would be what murf proposes to move all CDR (more than one for chained transfers) from the transferer to the transferee, having only its end time updated when posting (it would also make the CDR to be posted at the right time).

Could the actual CDR linked list structure be used, if nothing but the duration of each item of this list is updated when posting (leaving all other fields coming from older channels untouched)? Maybe even the forkCDR code could be re-used?

Murf, what complications would you see apart from probably breaking forkCDR functionality?

By: frawd (frawd) 2008-11-01 21:05:29

Excuse if the approach is too naive, having only been a few hours with CDRs I assume that it is wrong, please tell me why!

The idea would be to use the existing CDR linked list structure, which apparently is only used to store current and forked CDRs, to store inherited CDRs from transferers, to be posted at a later time. Whenever we have a transfer, and before hanging up (and posting CDRs) the transferer, we would move the CDRs from the transferer to the transferee only if they are related, otherwise leaving them on the transferer channel to be posted when the transfer completes.

The following simple scenarios illustrate the idea.

* Blind transfer:
1. A calls B: this bridge has CDR1 (A->B)
2. A blind transfers B to C: the new bridge has CDR2 (A->C) plus inherited CDR1 (A->B), CDR1 is not posted yet
3. B or C hangs up: CDR1 and CDR2 posted

Resulting CDRs:
CDR1 (A->B): start=1, end=3
CDR2 (A->C): start=2, end=3


* Attended transfer:
1. A calls B: this bridge has CDR1 (A->B)
2. A calls C: this bridge has CDR2 (A->C)
3. A transfers B to C: the new bridge has CDR1 + CDR2
4. B or C hangs up: CDR1 and CDR2 posted

Resulting CDRs:
CDR1 (A->B): start=1, end=4
CDR2 (A->C): start=2, end=4


* Chained transfer:
1. A calls B: this bridge has CDR1 (A->B)
2. A blind transfers B to C: the new bridge has CDR2 (A->C) + CDR1 (A->B)
3. C calls D: this bridge has CDR3 (C->D)
4. C transfers B to D: CDR2 is posted (not related to B or D), the new bridge remains with CDR3 (C->D) + CDR1 (A->B)
5. B hangs up: CDR1 and CDR2 posted

Resulting CDRs:
CDR1 (A->B): start=1, end=5
CDR2 (A->C): start=2, end=4
CDR3 (C->D): start=3, end=5

The attached patch show a new function, ast_cdr_transfer to be called on transfers (but where??), and a new flag AST_CDR_FLAG_INHERITED that prohibits changing anything to them but the end-time and duration when they are to be posted (like the AST_CDR_FLAG_LOCKED from forkCDR). Could it be useful in anyway?

By: Grey VoIP (greyvoip) 2008-11-01 23:38:13

frawd I think this is exactly the sort of discussion that should take place. The issue we are dealing with here is a design one so if we can come up with a good one perhaps we'd be able to get buy off on it.

As far as the linked CDR list it seems a bit complicated to me and I'm not so sure the mechanism is flexible enough to cope with all scenarios. I know this particular bug report is focused on two specific cases, being Blind and Attended Transfers, but if a new design, as oppossed to a fix, is going to be implemented it should be able to cope with every scenario we can think of.

In your Chained Transfer example I think that the CDRs required are:

[Format: <A number>, <B number>, <duration>]

1. A, B, 1 to 5
2. B, C, 2 to 4 (since this is a blind transfer A has asked B to call C)
3. C, D, 3 to 5

The complication to me is the fact that a single bridge could end up with a long list of CDRs and on each transfer Asterisk would need to look over the list and attempt to work out which CDRs are applying to channels that are still up and which CDRs should be posted for channels that have been hung up. I can see the logic getting pretty convoluted.

The solution I propose which is a 1-to-1 link between a CDR and each channel would make it very easy for Asterisk to determine when a CDR gets posted. Each time a channel is hung up a CDR is posted, that's it black and white and no chance of losing any information if a transfer or other application scenario comes up that wasn't anticipated.

Using that approach and with your Chained Transfer example the CDRs produced would be:

* = Asterisk

1. A (non-billable) , *, 1 to 2
2. * (accountcode=A), B, 1 to 5
3. * (accountcode=B), C, 2 to 4
4. C (non-billable) , *, 3 to 4
5. * (accountcode=C), D, 3 to 5

The example has 5 call legs and 5 CDRs.

If I was getting that information in the CDRs I would be able to bill correctly. An extra nicety would be a way to link all the calls together to show a more succinct call history to the user but that's a minor consideration compated to getting accurate accounting.

If incoming calls need to be billed, if for example you are a toll free number provider, then the chained transfer approach means a billing engine would have to start working out whether each CDR should generate two billing records or not. With the CDR per channel approach it's a simple matter of allocating an accountcode to the incoming call and putting a rate in.

By: David Woolley (davidw) 2008-11-02 03:01:36.000-0600

I don't think you can use account code for this.  You may be able to use ANI.

I think people are approaching this from the point of view of providers of public PSTN gateways, but for internal accounting purposes, within an organisation, account code is typically used by professional service companies to bill calls made on behalf of a client, but one also wants to be able to account the call to the person who physically made it.

More generally, I think there is a need for clear documentation of what the current CDR system is trying to do.  Even reading the code, I have trouble working out the purpose of ForkCDR, and came to the conclusion that ResetCDR does a better of job of what I originally thought it was for.

By: Grey VoIP (greyvoip) 2008-11-02 03:08:07.000-0600

Accountcode was an example you can use whatever you like. The critical thing is that dialed destination and duration are there and correct.

The CDR system needs to produce accurate call detail records, that's it, I don't think we need any documentation to say that. ForkCDR in some respects is an application conjured up to help overcome the lack of accurate CDR's in the first place (I realise there are other cases where it could get used as well).

By: David Woolley (davidw) 2008-11-02 03:08:48.000-0600

Another case where CDRs produce something less than useful is where a local channel gets optimised out.  Currently, you get an ANSWERED call for the ;2 side of the channel to the final destination, which ends when the call is answered and a NO ANSWER call, with valid end and answer times, for the call to the;1 side.

Some optimised local channel cases are internally generated, and even where explicit, the reason for optimising often means that the overall call is what you are really interested in.

By: frawd (frawd) 2008-11-02 06:08:07.000-0600

greyvoip, I still think in the chain transfer scenario we should have:

1. A, B, 1 to 5
2. A, C, 2 to 4
3. C, D, 3 to 5

instead of what you propose:

1. A, B, 1 to 5
2. B, C, 2 to 4
3. C, D, 3 to 5

Why? Because we cannot bill B for something he didn't do. When A blind transfers to C, it happens on A's context and it is like if A called C (just like in the attended transfer case). What if B didn't want to be transfered to C or is not aware of this transfer (ex: hotline blind transfering you to other service)? I understand in some cases you would want to bill B (operator connecting B to destination), in that case you can always relate easily with the second CDR having the same B channel id as the first one. What do you think?

As of the long list of CDRs associated with the channel, it would be exactly like if you used a forkCDR trick for each transfer (but in better as automated). I doubt you have lots of situations where a call is transfered so many times that the CDR list grows to affect performance, and in that case forkCDR tricks would be much worse. Remember that non-related CDRs are not inherited and posted.

The advantage is that it seems to be a very simple fix compared to a total redesign that is never going to make it into 1.4 (sorry, i need that fix now!). I just need to know where to call that function (do transfers happen in the channel drivers or just in res_features?).

About your proposal of 1-1 link from CDR to channel, it's probably the best idea for the future (1.6.*), but seems quite difficult to implement in current versions, and I see it a bit complicated for a billing system to relate channels together in order to bill actual calls (even tho it must be feasible adding new variables to the CDR or using ANI/Accountcode).

Thanks for the feedback, anyone knows how to remove that "LICENSE PENDING" thing (I sent my information using that form and don't know what happens next)?

By: David Woolley (davidw) 2008-11-02 07:47:05.000-0600

Whether one is likely to want to bill B or A, for parts of the call involving C depend on whether B is a customer or an agent of the network.  For an operator assisted call, one would normally want to charge A.  If the call were person to person, one might want to distinguish between the cost of calls made and the amount billable to A.



By: Grey VoIP (greyvoip) 2008-11-02 07:58:34.000-0600

frawd, yes you are right on the chained transfer cdr's, my mistake. I was thinking of the pure SIP World where a Blind Transfer uses a REFER request to tell the party at the end of the transfer that they should call a new destination. Asterisk does it differently and does use the leg initiating the transfer as the owner of the blind transfer call leg.

I suspect the 1-1 CDR's per channel would actually be an easier fix than the chained transfer scenario. In the 1-1 case it's stopping information being removed whereas the chained CDRs needs new structures added.

From what I have managed to garner the main source files dealing with bridging and transfers are channel.c and res_features.c. res_features.c is certainly being tweaked at the moment (probably by murf). I noticed the following block on line 233 has been removed from it between 1.4.19 to 1.4.22.

if (tobj->chan->cdr) {
ast_cdr_reset(tobj->chan->cdr, NULL);
ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
}
if (tobj->peer->cdr) {
ast_cdr_reset(tobj->peer->cdr, NULL);
ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
}

1.4.19 actually produces a CDR per channel as I'm suggesting it's just that the information in them is not correct.

As far as your license pending it's a manual process and someone from Digium will check and approve your license at some point. Just as a word of caution don't build up too high an expectation about getting patches accepted. I'm not meaning to discourage a contribution by any means but I've seen a very useful patch not accepted because it weren't deemed "necessary" due to future improvements providing an alternative. The particular patch was not as close to the core of Asterisk as what we're talking about here. That's the reason I'm so keen to get buy off on a design decision, cutting the code for this will be hard but doing it and then seeing it sit outside the main code base and having to apply it for each release would be even harder.

By: frawd (frawd) 2008-11-02 08:41:51.000-0600

Don't forget there is also a merge process between the cdr of two channels that are bridged that we would need to remove (and I really don't know about implications). I agree with the design, but I still think it can be complicated to implement (and it also means I have to rework all my external billing system). Don't get me wrong, I still want to help out to get this the best it can be in later versions, but I need this bug fixed ASAP in 1.4 for pending projects with ISPs.

The 10 lines function in the patch I uploaded shows it, no need for new structure unless I'm totally wrong (murf is the expert, and will tell us if it is a wrong approach). The CDRs in a channel are already in a linked list, used by forkCDR to store its locked copies, so no need to create new structures. What I did was just to add a new flag that tells if it was an inherited CDR (and leave forked CDRs alone without breaking this functionality). The rest is just a question of moving related CDRs from transferer to transferee, and leave the rest to be posted.

I hope on monday someone from Digium will contact me or allow my license signing for you guys to be able to check it out. If it happens to be a correct approach, I'd trust murf to get it applied in 1.4, as it was actually his idea. Note that it doesn't do anything as of now, because that new function is not called anywhere (need to figure out where to call it).

By: mdu113 (mdu113) 2008-11-03 09:49:01.000-0600

frawd, I love your approach. I've worked out several most common cases and they all seemed to be covered. Also with this approach I can see the potential to finally properly account for parked calls. Imagine if channel being connected to parked channel inherits its CDRs. Can't wait for murf to comment on it.

greyvoip, I think that your approach is probably more correct conceptually and I guess it will cover all possible scenarios including parking, but it will completely break all existing asterisk-based billing system. I think if that is to be implemented it should be added as an option. Both systems have to exists concurrently for some time, so that users have time for transition.

murf, i've tested your patch and sip transfers (the only ones I use). For sip transfers the BLINDTRANSFER variable is correctly set to transferrer. I would still suggest we use different variable name for attended transfer. Also regardless of what will be done with CDRs this can be useful by itself, so please don't discard this change.

By: Steve Murphy (murf) 2008-11-03 15:27:06.000-0600

Before I respond to any other input, I just want to say:

OK, folks, if it will help calm the troubled waters, a config file option
will be consulted , no matter what approach we might take. There will be no
change in current behavior unless you explicitly request it in a config file.

I simply cannot re-engineer the CDR flow; the emphasis is to make the minimal tweak to get done what needs to be done.

Give me a few days to evaluate all the nice ideas you brought forward, and I'll get back to you.

By: David Woolley (davidw) 2008-11-07 06:46:50.000-0600

As someone mentioned merging, it might be worth noting that ast_cdr_merge appears to be unused in 1.6.0.

By: Grey VoIP (greyvoip) 2008-11-15 02:06:03.000-0600

Hi frawd, I had a crack at applying your patch. Should it work with 1.4.22? I get a compilation error on cdr.c.

cdr.c.521: error: structure has no member named 'channel'

Your patch is updating cdr.h and cdr.c is there also an update required to channel.h maybe?

By: frawd (frawd) 2008-11-17 09:03:03.000-0600

Hi greyvoip, this patch was just an idea for a new function on cdr.c, to be called whenever there is a transfer.

I didn't even test applying and compiling with it, and being just a function, it doesn't do or correct anything. I will try to improve (including channel.h is probably not the way to go if not already there) and test that with SIP transfers (now that I know more or less where those things happen) as soon as I have a bit of time (maybe next weekend).

Having already lost a project thanks to that issue and being unable to lie to my clients for stupid trust issues, I had time to wait for some expert's feedback (to check if I'm wasting my time or not), but apparently our master is or seems dead. New projects are coming and I'll soon have to make that issue a priority if I have brain enough to understand as much as Murf what's going on with those CDRs.
In last resort, I heard that Freeswitch had a better channel-event system but it would be a pain to switch for many reasons (ex: I really like Asterisk's logo, and love that bad feeling when reading chan_sip.c).

By: tony (tony) 2008-11-19 03:02:55.000-0600

hi, i'm having the same problem with tranfers. For when do you think the issue will be resolved? thanks

By: Steve Murphy (murf) 2008-12-01 14:53:52.000-0600

OK; The only way we can settle this issue once and for all is literally to
rewrite CDRs. I've come to that firm conclusion. The existing CDR system is
tightly integrated into the Channel/Peer philosophy, and the problem almost
insoluble, to generalize to the extent that we have.

The best to way approach this is to generate CDR/leg, where the timing is from
leg to leg, in conjuction with a 'linkedID', that would tie the legs together
into a logical call.

I have a spec underway that you can fetch via
svn co http://svn.digium.com/svn/asterisk/team/murf/RFCs
called CDRfix2.rfc.txt, the only file in that directory.
Please read it with a critical attitude and a wary eye, and feel
feel to roast it alive. Send me the nitpicks, the gaps and flaws
in thought, the cool nifty new ideas, whatever.
Right now, it's being discussed in the asterisk-users mailing list under
"CDR Desgin" (pardon the typo)

By: frawd (frawd) 2009-01-12 11:51:16.000-0600

Hi, I'm back on this bug and should be able to post soon a small testing patch using the idea of CDR inheritance.

Anyone willing to help me for testing? (I think I'll first try on SIP attended transfers).

By: mdu113 (mdu113) 2009-01-12 12:44:41.000-0600

frawd, I'm willing to help any way I can, testing included.
I love your idea and if it works it will be minimally intrusive change that should fix most of my cdr problems.

By: Steve Murphy (murf) 2009-01-23 12:44:38.000-0600

frawd, mdu113, any results on testing frawds work on CDR inheritance?

I've upgraded the CDRfix2 doc to include "Simple" (greyman's) concept,
and a "Leg-Based" approach for those with more complex needs.

I'll be re-reading all the conversation above once more. Right now,
a lot of little bugs to close in relation to CDR's.

By: frawd (frawd) 2009-01-28 07:28:52.000-0600

Hi and sorry for not answering before.

I have been doing many and wannabe patches (refreshing my C skills), and I could make my idea work perfectly for attended transfers in SIP. I tried with dozens of chained attended transfers and the result was the expected one.

The problem that stopped me was for blind transfers. What asterisk does in that case (still talking about SIP) is to hangup the transferer and running an asyncronous goto on the transferee, like if the transferee was doing a new call with the same channel ID.
It then seems quite impossible to inherit CDRs in such case, as the channel is reseted after the goto (and all CDR inherited are then lost).

More or less, it means that the original "light" job is converting itself in something much bigger and likely to introduce bugs and such. I will then need more time to investigate and patch that thing, hoping that nothing is really impossible. Sorry for breaking expectations :-(

By: Steve Murphy (murf) 2009-01-28 10:07:21.000-0600

Welcome to CDR land!

I've come to the conclusion that storing CDR's on a channel is not the way to go. The operations done to channels pose some logically impossible choices. It kinda reminds me of Quantum Mechanics; and the fate of coupled photons, but in our case, nothing ties our photons (channels) together-- A masquerade shifts the guts of a channel into a new channel, and the new channel even gets the name. The old channel, stripped of all its active info, including its name (it gets a ZOMBIE added to its old name), is left to die. It is meant for the two versions of the channel to be owned by different threads.  Either one could actually die and be destroyed before the other. The new channel gets the CDR. The old one keeps the PBX pointer. The new channel is now a "peer". This works fine for parking, but other cases... well, not so well.  If a hangup occurs for the new channel, the old channel neither knows nor cares. Yes, you could look up a channel by name, but... that's a really, really, expensive and odious procedure, and there's no guarantee you'll find it... it might have been destroyed already!

There is no universally acceptable solution to which channel in a masquerade should get what info; indeed, in some cases you won't know until one of the channels is dying, or reconnected. That's why I think CEL is the way to go. You are at a level above the channels, independent of them, with snapshots of the data that was stored on the channel at that moment. You have the power to select what channel info goes into a CDR. My chief challenges will be to recognize patterns and generate the proper CDRs from them. CEL will gather all the events from all the channels involved, and can easily decide what to do in retrospect. If we spot a gotcha, I can refine the matching alg.

I've been thinking about another possible approach, where we build into the transfer code the decisions about where things should be shuffled between interacting channels. There are points in the code where you have pointers to all the interacting channels at once, and these would be good places to make sure the CDR data gets shuffled around, but even this approach is subject to the  weakness that you can't make decisions before you know the outcomes, and thus possibly this approach would fail also.

Add to all this the fact that code paths overlap in the pbx engine, and the nice and elegant generality of the situation hides particular cases you might need to discern. And the fact that "peer" and "channel" roles are hard-wired into the various function calls, and it's not at all clear how to handle colliding/changing peer/channel relationships...

And, add to that the "simple" running of the h (hangup) extension in the dialplan when certain (channel role) channels are being hung up... and the combinatorial mess that results when xfers, parks, etc happen is just ... breathtaking. You see, masquerades don't always happen in all situations in the course of xfers... so....

I love challenges, but tweaking is no longer an option. It's time to rewrite.

But, I don't want to discourage innovation-- if someone finds a magic solution, I don't want to discourage them from trying...



By: mdu113 (mdu113) 2009-01-28 10:22:01.000-0600

Hi,
Rewrite may be the best option, but somehow I feel it's long before the point when  new cdr system can be used. So my 2 cents would be that for the time being having at least attended transfers to be accounted properly is much better than having  broken cdrs for all kind of transfers.

By: Steve Murphy (murf) 2009-01-28 10:35:53.000-0600

OK, I'll give it my best shot, but I need to clear a lot of CDR-related bugs out of the queue over the next few days. And each one could affect this situation; I'm trying to make them specific, and they hopefully will not, but I'm being realistic, also.

So, according to my notes, you may be interested in changes (patches) on 12876, 13691, 13794, 13892, 14241. After these are in, I'll review this one again.

At some point, we may have to declare some situations as insoluable (practically, anyway). We'll see.

By: Steve Murphy (murf) 2009-02-11 14:51:58.000-0600

OK, there is a window of opportunity here, I think!

I'm currently working on a fix for 13892; and due to the intertwinement [is that an official English word?) of the CDR system in Asterisk, my fixes cause regressions, which require fixes that cause other regressions, etc. Anyway, they reached into the behavior of both the blind xfer and the attended transfer. The blind xfer was pretty easy to restore, but the attended xfer is really whacked out, (my current case is where A calls B, and B axfers A to C), generating 4 CDRs, with 8 unique start, ans, end times, involving a local channel pair, and masquerades on both sides of the two local channels involved; A total of 9 CDR's; 4 bridge CDRs and 5 involved channels.

This is what I think you would want to see in this case:

CDR1: chan: A; dstchan: B; st: when A picks up or arrives; ans: when B ans;
     end: when C hangs up (used to be when B finished the xfer)
CDR2: chan: B; dstchan: C; st: when C starts ringing; ans: when C ans;
     end: when A/C hang up.

In the case where A calls B, A attended-xfers B to C, this is what I
think you want in this case:

CDR1: chan: A; dstchan: B; st: when A picks up or arrives; ans: when B ans;
     end: when C hangs up (used to be when A finished the xfer)
CDR2: chan: A; dstchan: C; st: when C starts ringing; ans: when C ans;
     end: when B/C hang up. (there is no room in the CDR to express that
     B and C were connected during this CDR's timespan)

Is this correct? I can't guarantee that I can pull this off; if it involves too much channel-foo outside the attended xfer func, I may to leave it at the way-it-used-to-be; we shall see.

You can see where I'm at if you play with the d14.dig1 patch on 1.4 svn (attached to 13892) . The rules are simple: do everything in the attended xfer func in res_features.c, or forget it.

By: mdu113 (mdu113) 2009-02-11 15:35:07.000-0600

Looks correct to me.

By: David Brillert (aragon) 2009-02-16 18:00:54.000-0600

Hi Murf

I know you must be working madly at this ;)

I'm curious if you will be posting or possibly implementing a patch before Asterisk 1.4.24 is released? I didn't see anything related to this on 1.4.24 roadmap.

By: Steve Murphy (murf) 2009-02-16 23:14:35.000-0600

No, I cannot expect that the next release will contain the set of fixes I'm working on now. Change one thing, and you have to change a bunch of things. To get what we want, I have to make changes in several places. And the effects of a change reach out and touch other parts of the system. That's the deal with systems built in-line like this. And why I abominate them.

The current situation stands this way: I've made significant improvements and fixed several problems, but the fixes broke both the blind transfer and attended transfers. I fixed the blind transfer mechanism to behave the same braindead way it used to, but that's not easily done with attended transfers. It's a delightfully interwoven sequence of local channels, masquerading, and multiple threads. For instance, the last part, where the transferred party and the transferee converse, is done in its own thread. The dial operation to the transferee is done in the realms of executing the dialplan to get the end party via a local channel -- after all, you might just as easily have transferred the party to a recording as to another extension. In my manipulations, I see from 3 to 5 CDRs, all of them garbage, and the two I *WANT* to publish get tossed!

Well, this is an all-or-nothing sort of situation. I can't release the fix with attended transfers braindead; I'd be better off tossing the whole wad and closing all the bugs. On the other hand, I'm understanding all the mechanics and their consequences more and more as I tinker and experiment and study them. I feel like what I want to do is doable; I simply have to turn off all the CDR's that normally would be generated, and allow the two I'm building in the atxfer routine to get posted. Couldn't be simpler, eh?

Well, if I can achieve this with atxfer, then I need to revisit the blind xfer, and get that to do the same also. It's just that it operates a fairly different way. No local channel. Just an asyncgoto. I'll have to suppress the CDR's that normally would be output, and generate the two (pretty much the same stuff) that I would with the attended xfer.

If anyone is interested, I can attach a patch that will give you exactly what I am working on at present. It has one main problem-- a crash when the tranferee (the party "C") answers the call (A calls B, and A xfers B to C). The crash is because the CDR pointer is corrupted, which normally would imply the channel has been destroyed, and freed, reallocated for something else, and the cdr pointer overwritten. Which, btw, is not really very good news. I've got 5 pages of notes on the subject already, not including the dozens of sets of log message outputs I've captured and analyzed so far, each capturing a little more state over the last, as I insert more and more debug tracing. It's a matter of tracing the unique ID's, and CDR pointers, as a lot of cdr's internally are copies of each other and share the same unique ID's. There's a zombie or two to watch out for in the mix as well, the makings of a real horror story!

Oh, and because two CDR's are getting generated, that creates somewhat of an ambiguous situation for when the h-exten is run on C when it gets hung up. Which CDR will you be seeing and able to mod when the hangup routine runs? This is new territory! A is the only dialing party in this particular sequence, but he's called both B and C. Now, A is hung up while B and C converse, but A is the guy responsible for both calls, so his h-exten needs to be saved to coincide with the publishing of the two CDR's. This is so against the philosophy of the h-exten running philosophy, yet it needs to be, as most people use the h-exten to tweak the CDR going out the door... The philosophy is all wrong in this instance. The h-exten is run on all closing channels; it really shouldn't have been tied to CDR's.  If we were smart, we'd define a CDR extension, and a before a CDR got posted, it would get run. Only problem with that is: the channel the CDR might be associated with could be gone. How do you execute dialplan without a channel? Well, OK, at hangup time for B and C, we could execute the h-exten for them; that's a little complicated by the fact that B and C are both peers, and don't have a pbx associated with them! Hmmm, are you getting a feel for what I'm playing with?


And, all the while, I'm haunted by the following questions: is it worth it? Will the code really be better? Will we as devs and users really be benefited by what I'm doing? If I can pull it off, you guys wanting valid CDRs will definitely be benefited, but at a high price to me and the code, I'm afraid!

Ok, enough said. I've got at least another week of work ahead of me, and I still can't guarantee that I can deliver what everybody wants: working h-exten, CDR's the way we described, and no bad/unwanted CDR's.  Maybe I can, maybe I can't. That's the honest truth at the moment.

All I can hope is that I find some good, solid places to make some good, solid, reasonable tweaks that will get us what we need, and not louse up everything I've already accomplished!

By: Sverre G (sverre) 2009-02-25 07:58:49.000-0600

I  have been carefully watching this thread recently, having come up against the exact same issue. The thing is, blind transfers are not the issue, putting one of the unique id's into the userfield allows the linking of two CDRs that have been blind transferred.

The issue is only with attended transfers, because the moment BEFORE the attended transfer takes place, they are two completely separate calls - two unrelated CDRs in the making. The moment the SIP client sends the SIP REFER however, one of the channels is dropped (ending the CDR timing on one of the two), but no detectable event takes place on the Asterisk side that allows you to set the userfield to the other channels uniqueid.

If there was just a variable ${ATTENDEDTRANSFER} made available to the h extension in the same vein as ${BLINDTRANSFER} is made available, then we could solve the CDR problem at a dial plan level as a workaround until NewCDR gets merged, and that wouldn't conflict with anything else.

It's worth noting that on discovering this issue, I did an experiment with my local VoIP provider, and it turns out they are not charging for the correct length of calls when a transfer occurs. This is a SEVERE bug that exposes VoIP providers using Asterisk to potentially thousands of dollars of international calls without any system for billing them to a customer.



By: Leif Madsen (lmadsen) 2009-02-26 17:22:36.000-0600

I'm updating this by marking this issue as targeted for 1.4.25 just so we have an end goal for what 1.4.25 might contain, but this may change as we move forward.

By: Sverre G (sverre) 2009-03-02 21:07:14.000-0600

I've just added two agi scripts written in php, attendedtransfer.agi and settransferfield.agi that allow you to create a link from the prematurely ending CDR to the continuing CDR with the idea that you can post process the CDR after the fact.

It works for me on 1.4.22, no idea if it works on other versions.

You will need to add the field transferfield to your CDR MySQL table, you'll need to change the MySQL username and password in settransferfield.agi, and you'll need to call the AGI script from your dialplan, for example:

exten => h,1,DeadAGI(attendedtransfer.agi)
exten => h,n,GotoIf($[${LEN(${CHANNELDSTFROM})} > 0]?attendedtransfer)
exten => h,n,MacroExit()
exten => h,n(attendedtransfer),DeadAGI(settransferfield.agi,${CHANNELDSTTO},${CHANNELDSTFROM})

You probably want to wrap that in some kind of check for a blind transfer (use the ${BLINDTRANFER} variable to find out, and then call settransferfield.agi in that scenario as well - but I haven't gotten that far yet.

I've tested it in the following scenarios:

A->B, A->C, Transfer
A->B, A->C, swap, transfer
A->B, C->A, transfer
A->B, C->A, swap, transfer
B->A, A->C, transfer
B->A, A->C, swap, transfer
B->A, C->A, transfer
B->A, C->A, swap, transfer

I've NOT tested it with two sequential transfers.

Some important notes:

This script is a dirty hack, and it's not written very well. In hindsight, I should have tested for each of the 8 above scenarios and done a case statement. As it is, it's a bunch of nested if's. I programmed one scenario and figured it would work on all, then started adding exceptions and ended up with this as the result. If i make a neater version, I'll post it here.

The settransferfield.agi could perhaps have used the existing MySQL link, but it was easier to use php's inbuilt mysql functions.

There are NO GUARANTEES about anything here. If it works for you, great. If not, don't use it, or better yet, revise it.

It figures out which of the above scenarios is happening by calling asterisk at the command line with a "show channel XYZ" command, and extracting information from that. I've had to use things like the number of DIALEDPEER, BRIDGEPEER variables present, and link to other channels by their contents. This makes this hack EXTREMELY SUSCEPTIBLE to changes in the show channel command. Even changing the order of reported variables will give weird results. Use it at your own risk.

By: Sverre G (sverre) 2009-03-03 01:33:23.000-0600

Here's a replacement dialplan to refer to the two agi's. This version also covers blind transfers, it differentiates between A->B, transfer to C and B->A, transfer to C (where A is doing the transfer in both cases), by seeing if the DEST and CDR(dst) fields match or not. It's important because these two scenarios are handled differently in the CDR.

exten => h,1,GotoIf($[${LEN(${BLINDTRANSFER})} > 0 & ${LEN(${SIPTRANSFER})} > 0]?blindtransfer)
exten => h,n,DeadAGI(attendedtransfer.agi)
exten => h,n,GotoIf($[${LEN(${CHANNELDSTFROM})} > 0]?attendedtransfer)
exten => h,n,MacroExit()
exten => h,n(attendedtransfer),DeadAGI(settransferfield.agi,${CHANNELDSTTO},${CHANNELDSTFROM})
exten => h,n,MacroExit()
exten => h,n(blindtransfer),GoToIf($["${DEST}" = "${CDR(dst)}"]?same:different)
exten => h,n(same),Set(CHANNELDSTTO=${BRIDGEPEER})
exten => h,n,Set(CHANNELDSTFROM=${CHANNEL})
exten => h,n,DeadAGI(settransferfield.agi,${CHANNELDSTTO},${CHANNELDSTFROM})
exten => h,n,MacroExit()
exten => h,n(different),Set(CHANNELDSTTO=${BRIDGEPEER})
exten => h,n,Set(CHANNELDSTFROM=${BLINDTRANSFER})
exten => h,n,DeadAGI(settransferfield.agi,${CHANNELDSTTO},${CHANNELDSTFROM})
exten => h,n,MacroExit()

By: Leif Madsen (lmadsen) 2009-03-03 13:15:19.000-0600

sverre: a suggestion I have would be to use the manager API instead of doing a system command to retrieve information via the CLI. You'll find you may get some improper characters that could mess up your script on active systems.

By: Sverre G (sverre) 2009-03-03 15:56:07.000-0600

Thanks lmadsen, I did look at using the manager - and I agree it would be better - but when I started this process I found I had to depend on quirks from the CLI to differentiate between scenarios. There may be an API solution, but I don't want to commit a lot of time to it when the CDRs are expected to be fixed properly in 1.4.25.

By: Leif Madsen (lmadsen) 2009-03-03 19:15:56.000-0600

sverre: fair enough -- thanks for contributing!

By: Matthew Nicholson (mnicholson) 2009-05-18 13:11:31

Is this still a problem with the latest 1.4 SVN?  I cannot reproduce this using sip channels with transfers.  It seems to work correctly.  Does this problem only occur with dahdi channels?

By: Sverre G (sverre) 2009-05-25 20:22:33

Yes, definitely still a problem in SVN-branch-1.4-r196116

I placed a call from 102 -> 101, spoke for 10 seconds, placed that call on hold.

I then placed a call from 102 -> 103, spoke for 10 seconds, and then hit transfer (connecting 101 and 103).

There are two resulting CDRs, which is correct, but the billsec of 102->103 is only 20 seconds, which is not correct. The CDR for 102->101 is OK however.

Imagine if a user called Antartica first, put that on hold, called Greenland second, and then done the transfer and connected those callers - who had then spoken for 4 hours. Sure I'd have billed them correctly for the call to Antartica, but the call to Greenland would have been nearly free for the user, meanwhile my VSP will happily bill me for both calls.

By: Matthew Nicholson (mnicholson) 2009-05-29 17:59:20

I was not able to reproduce this.  Billsec looked correct during my tests.  Using your example, I called from 102 -> 101, spoke for 5 secs, pressed transfer to place that call on hold.  I then called from 102 -> 103, spoke for 5 seconds, pressed transfer to bridge 101 and 103.  The first CDR was written with billsec of 15 (I spent 5 seconds dialing).  101 and 103 spoke for 5 seconds and then hungup.  The second CDR record is written with a bill sec of 10 seconds.

This all seems correct to me.  I tested with SVN-branch-1.4-r198068.

Please test again with the latest 1.4 SVN branch, also please post the full CDR records from both legs of the call.

By: Sverre G (sverre) 2009-05-30 20:39:30

Can you try this for me mnicholson?

Call 102 -> 101, speak for 5 seconds, then transfer the call to 103. Have 102 and 103 speak for 1000 seconds.

BOTH cdr's should be in the 1000 second range, not just one of them.

This is because the call may well be 102 -> 1100 67 1234 5678 (papua new guinea), transfer to 1100 68 2345 6789 (cook islands). In this case, our asterisk box is maintaining _2_ outbound (and really really expensive) calls, and we need to pass the cost of both on to our customer.

By: Matthew Nicholson (mnicholson) 2009-06-01 17:25:09

I understand your reasoning there, but unfortunately, I don't think the current CDR model can handle cases like this.  The planned CDR rewrite will handle this case.

Give me a few days to think this through and see if I can come up with a work around for you.

By: Sverre G (sverre) 2009-06-01 18:02:41

Yes this was my understanding as well, that we're waiting on the CDR rewrite to fix it.

In the mean time, I've updated the AGI scripts I posted a while ago which adds a "transferto" field to a MySQL based CDR record. In the original (and posted version), the transferto field points to the dstchannel of the continuing CDR, however this version didn't work in all circumstances.

I have a new version which I will post shortly that uses the transferto field to point to the uniqueid field.

Either way the result is that by doing a self join in MySQL, you can have a field called newbillsec which is equal to cdr_1.billsec + cdr_2.billsec, which means that you end up with one 2000 second CDR, and one 2005 second CDR - exactly what I need.

It would be better if CDRs natively supported the transferto field that I've created, but depending on how far NewCDR is it could be a waste of effort. So I perceive there are 3 solutions:

1. Use my AGI scripts as a workaround
2. Add native support for transferfield as a workaround
3. Finish NewCDR

By: Sverre G (sverre) 2009-06-02 19:18:45

As promised, I've uploaded the version 2 of my AGI scripts - which is a hack workaround to make sure Asterisk user's customer's aren't able to make expensive phone calls without getting billed.

Some notes:
- It depends on MySQL CDRs
- It depends on having populated uniqueid's
- It comes with no warranty and no support
- It could probably be done better another way, but it works

Installation
- Remove "v2-" from the front of the file names
- Put the AGI files in /var/lib/asterisk/agi-bin/
- Edit them to change database username/password
- Give them permissions (e.g. rwxr-xr-x)
- Call them from extensions.conf
- Add the field transferto to your cdr table in MySql

Extensions.conf

exten => h,1,Macro(transfers)
; You probably need this in both your outgoing and incoming contexts

[macro-transfers]
exten => s,1,GotoIf($[${LEN(${BLINDTRANSFER})} > 0]?blindtransfer)
exten => s,n,DeadAGI(attendedtransfer.agi)
exten => s,n,GotoIf($[${LEN(${UNIQUEIDTO})} > 0]?attendedtransfer)
exten => s,n,MacroExit()
exten => s,n(attendedtransfer),DeadAGI(settransferfield.agi,${UNIQUEID},${UNIQUEIDTO})
exten => s,n,MacroExit()
exten => s,n(blindtransfer),DeadAGI(blindtransfer.agi)
exten => s,n,DeadAGI(settransferfield.agi,${UNIQUEIDFROM},${UNIQUEIDTO})
exten => s,n,MacroExit()

How it works (attended transfers):
- When an attended transfer completes, the ending CDR points to the continuing CDR by way of the BRIDGEPEER variable. By looking up that channel information, the UNIQUEID can be retrieved to go in the MySQL transferto field of the ending CDR.
- Different circumstances change exactly where to retrieve the UNIQUEID from, but the circumstance can be deduced from the contents of the channel information.

How it works (blind transfers):
- In some cases, same as above
- In other cases, the uniqueid of the two CDR's is the SAME, and in that scenario the AGI calls "setuniqueid.agi" to change one of them before linking them

By: Matthew Nicholson (mnicholson) 2009-06-03 18:05:04

Workarounds like the one you have described here are basically the only way to handle this situation given the present CDR architecture.  CDR records are currently very bridge centric, but to satisfy your requirements, a cdr record would need to be generated for each channel.  This sort of thing will be possible with future versions of asterisk 1.6.

By: Sverre G (sverre) 2009-06-03 18:36:19

I mentioned it earlier but it's worth repeating. I have accounts with a number of SIP providers that use Asterisk. I have verified that I can currently make near free mobile or international calls by placing the call, then doing a transfer to a local number. The timer for the mobile call stops, and the local call is a flat rate.

I've heard stories of hacked Asterisk machines being used to place huge numbers of expensive international calls, so there's clearly a motivation for people with malicious intent to exploit this security hole.

By: Matthew Nicholson (mnicholson) 2009-06-03 18:42:50

Yes I saw that.  I am aware of this, and it is a fairly serious problem.  Unfortunately, this can only be fixed in future 1.6 asterisk releases, without dramatically changing the way CDR records are generated.

This could be fixed if there was one CDR record generated per bridge, and one generated per channel, but this could potentially break existing billing systems.  Perhaps this could be added as an optional feature.

Would generating one CDR record per channel resolve this issue for you?

By: Sverre G (sverre) 2009-06-03 19:04:16

I can think of a few scenarios where having 1 CDR per channel would be superior. Currently when one customer calls another customer on Asterisk, the "incoming" CDR for the destination customer is missing (only 1 CDR to share between two customers, and we'd rather keep the billable outgoing one!).

That being said, I can't figure out in my mind how we would figure out which channels are billable and which aren't - in most cases you'd only want to bill for 1 of the 2, though I'm sure there'd be a way.

I'm going to say "yes it would resolve it", but I imagine there'd be quite a process in figuring out how to implement a billing system around it.

Given that people can use my hack workaround to fix the problem for now, my feeling is that any time spent fixing the current CDR system is time that could be spent on the new CDR system, though it depends on how far off it is. If we can expect to see it in the next month or so, I wouldn't worry about it. If it's going to be 6 months on the other hand, then yes I'd start playing with one CDR per channel.

By: Matthew Nicholson (mnicholson) 2009-06-24 17:56:40

This bug is being closed as won't fix in anticipation of channel event logging being released with Asterisk 1.6.3.  Channel event logging will allow for properly tracking and billing channels that are transfered one or many times.  This bug will NOT be fixed in Asterisk 1.4.