root/doc/PREPAID.txt

Revision 1074, 13.3 kB (checked in by Adrian Georgescu <ag@…>, 5 weeks ago)

spellcheck

Line 
1
2Prepaid functionality is achieved by:
3
41. An external session control module, not provided by CDRTool, that
5maintains the session status and terminates the sessions by sending BYE
6messages to both SIP end-points. The session control module communicates
7with both the SIP Proxy and CDRTool using the API described below.
8
92. CDRTool rating engine - provides session management, calculates maximum
10session time based on user balance and destination using the same algorithm
11as the postpaid engine and debits the subscriber balance.
12
13See doc/PrepaidEngine.pdf for a detailed session flow.
14
15
16Prepaid API
17-----------
18
19CDRTool prepaid engine is used to compute session times based on user
20balance and destination dependent rates and debit the balance when the
21session has ended. The prepaid engine is accessible over the TCP socket
22where the rating engine listens.
23
24The TCP socket location is configured in /etc/default/cdrtool. The
25connection can be tested manually using the telnet command and by typing
26help at the prompt:
27
28tstuser@host:~$ telnet 10.0.0.0.1 9024
29Trying 10.0.0.1...
30Connected to 10.0.0.1.
31Escape character is '^]'.
32Help
33MaxSessionTime        CallId=6432622xvv@1 From=sip:123@example.com To=sip:0031650222333@example.com Duration=7200 Gateway=10.0.0.1 Lock=1
34ShowPrice             From=sip:123@example.com To=sip:0031650222333@example.com Gateway=10.0.0.1 Duration=59
35DebitBalance          CallId=6432622xvv@1 From=sip:123@example.com To=sip:0031650222333@example.com Gateway=10.0.0.1 Duration=59
36AddBalance            From=123@example.com Value=10.00
37GetBalance            From=123@example.com
38GetBalanceHistory     From=123@example.com
39DeleteBalance         From=123@example.com
40DeleteBalanceHistory  From=123@example.com
41
42In the example above only the commands related to the prepaid functionality
43are highlighted.
44
45The session control module must send commands based on the syntax described
46below, to the CDRTool prepaid engine. A command is a line of text containing
47a keyword, which is the command itself followed by a number of parameters
48separated by space. The command ends with an enter in unix style: '\n' For
49each such request there will be a reply on one or more lines, containing
50information that depends on the command that was sent. A reply ends when a
51double end of line (\n) is received: \n\n (this is needed because there are
52commands that require multiline responses). How the information contained in
53a reply is to be interpreted depends on the command itself and is described
54below.
55
56
571. Asking for the session time limit
58   ------------------------------
59
60To request the maximum time for a new session, the following request must be
61sent to CDRTool rating engine on one line:
62
63MaxSessionTime CallId=6432622xvv@1 From=sip:123@example.com
64To=sip:0031650222@example.com Duration=7200 Gateway=81.20.68.10
65ENUMtl=tld.com\n
66
67MaxSessionTime request is created when a new INVITE arrives at the SIP
68Proxy/session control application. Depending on the session setup time, the
69maximum session time might not be accurate because the session setup time is
70unknown at the INVITE stage. You can call MaxSessionTime again when the
71session has been setup (the OK has been received), in which case the rating
72engine will provide the updated maximum session time for the session that
73was in progress.
74
75Duration is a limit imposed to the time allowed, in case you want to limit
76the session time to a maximum duration. This will be a top limit for the
77session's time, even if the user could talk more than that based on his
78current balance. The session control module may limit all sessions to 7200
79seconds for example.
80
81To may actually be sip:number@domain;param=value so you must extract the
82username part which is the number From is a sip URI which can be "full
83name".
84
85ENUMtld parameter is optional but if present discounts based on ENUM can be
86applied (see RATING.txt for more information on ENUM discounts).
87
88Call control expects a reply like below:
89
90value\n\n
91
92value is the numeric time in seconds, or None, None meaning it's not a
93prepaid account and it doesn't have any limitation, or it's a free
94destination, like a 0800 number.
95
96To field must be the canonical destination SIP URI after all possible
97lookups in the SIP Proxy.
98
992. Debiting the balance when the conversation ends
100   -----------------------------------------------
101
102To debit money from the user balance when the conversation ends, the session
103control module must send the following command on one line:
104
105DebitBalance CallId=6432622xvv@1 From=sip:123@example.com
106To=sip:0031650222@example.com Gateway=81.20.68.10 Duration=59\n
107
108Same notes about the From and To fields as above apply. The call id must
109match the call id provided to the correspondent MaxSessionTime command.
110
111and expects in return:
112
113value
114maxsessiontime\n\n
115
116where value is one of: OK (success), Failed (failure), Not Prepaid (account
117is not prepaid - this case is not considered a failure).
118
119The second line contains the new maximum session time that is valid after
120debiting the balance for this session. It can be used to update the maximum
121session time of other sessions that are already in progress for the same
122user.
123
124Note that once your have called once MaxSessiontime, you must also call the
125correspondent DebitBalance even if the session has zero seconds duration. If
126you do not do this, the session will stay in progress for the maximum
127session time and any subsequent session setup will have its maximum duration
128altered by this existing session in progress. Sessions in progress will be
129automatically purged after they expire when a new MaxSessionTime request for
130the same user is received.
131
132The debited value and the new balance is recorded in the prepaid_history
133table.
134
135If the session does not exist, no balance will be debited. To force the
136DebitBalance to debit the balance even if no session in progress exists, you
137can supply Force=1 parameter. This can be useful if for some reason the
138requests have been lost due to network problems. In such case the requests
139can be applied at a later time.
140
141
142Prepaid ongoing sessions
143------------------------
144
145To see the sessions in progress go to Rating -> Prepaid.
146
147Fill in the Sesssions field: >0 and click Search.
148
149
150Third party tools
151-----------------
152
153FreeRADIUS-CDRTool by Dan-Cristian Bogos
154
155FreeRADIUS module providing connectivity to CDRTool prepaid engine. Provides
156prepaid authentication for sessions proxied by OpenSER and returns to OpenSER
157MaxCallDuration and user Credit. Can be easily extended to support other SIP
158or H323 devices.
159
160http://sourceforge.net/projects/frad-cdrtool
161
162
163Notes
164-----
165
166The balance is debited correctly regardless of the moment of CDR
167normalization. Renormalization of sessions do not recalculate balance.
168
169
170Simultaneous prepaid sessions
171-----------------------------
172
173Since version 6.6.0 is possible to have multiple sessions using the same
174prepaid account without the risk of reaching a negative balance.
175
176The modus operandi is based on a simple model: all prepaid sessions
177belonging to the same account must end at the same moment regadless of the
178called destinations and their different prices. The rating engine simply
179calculates that moment based on the data available from ongoing sessions,
180available balance and the new session setup request. This scheme provides a
181fair balancing policy with small performance penalty on the servers.
182
183By using this simple model there is no need to poll any database during
184ongoing sessions, which could become major scalability problem. All the work
185is done only once at session setup time. This will increase the load on the
186rating engine only during session setup and only for the users that have
187parallel sessions, the rating engine will perform internally during each
188session setup 2 x the number of sessions sessions to ShowPrice and
189MaxSessionTime functions. To be entirely accurate the session control must
190also connect back to the rating engine when the session has been setup so
191that the session expiration can be updated.
192
193You must set $RatingEngine['prepaid_lock'] to 0 in etc/cdrtool/global.inc
194and update the session control software module that keeps track of the
195maximum session time to enforce session ending for all sessions belonging to
196the same sip account at the same time based on the last value of
197MaxSessionTime received from the rating engine. The previous version
198required the session control module to keep the time counter per sip
199session, now it needs to sync the counter for all sessions belonging to the
200same sip account. See below the pseudo code for the session control engine.
201
202The list of ongoing prepaid sessions can be monitored in the Prepaid
203accounts section of the Rating pages. For each sip account that has ongoing
204sessions a link marked Sessions apears in the left side of the prepaid
205record. Click on it to display the ongoing prepaid sessions. The 'Delete
206session' button allows the removal of the session form the rating engine.
207The expired sessions that have not been closed properly by the session
208control module are automatically purged 120 seconds after expiration, which
209has been chosen to cover a reasonable session setup time.
210
211The time and balance distribution between parallel sessions is logged
212detailed in the syslog:
213
214cdrtool[13292]: MaxSessionTime From=sip:adi@umts.ro Lock=1 To=sip:00318008185@umts.ro CallId=waaivgq89aTxmPIG6JIsPhODUe0tRVf- Duration=36000 Gateway=80.101.96.20
215cdrtool[13292]: ConnectFee=0.0450 Span=1 Duration=16 DestId=31646 default Profile=442 Period=weekend Rate=442 Interval=0-24 Cost=0.1600/60 Price=0.0427
216cdrtool[13292]: Ongoing prepaid session uw1znivnqoeofyezzuiiisudukw64cm- for adi@umts.ro to sip:0031646999425@umts.ro: duration=16, price=0.0877
217cdrtool[13292]: Balance for adi@umts.ro having 1 ongoing sessions: database=9.9534, due=0.0877, real=9.8657
218cdrtool[13292]: Maximum duration for adi@umts.ro to destination 31646 having balance=9.8657 is 3700
219cdrtool[13292]: Maximum duration for adi@umts.ro to destination 31800 having balance=9.8657 is 29597
220cdrtool[13292]: Maximum duration agregated for adi@umts.ro is (Balance=9.8657)/(Sum of price per second for each destination=0.0030)=3288 s
221cdrtool[13292]: CallId=waaivgq89atxmpig6jisphodue0trvf- BillingParty=adi@umts.ro DestId=31800 Balance=9.8657 MaxSessionTime=3288 Spans=2
222
223
224Pseudo-code for rating engine
225-----------------------------
226
227This code is actually implemented in cdrtool.
228
229max_session_time (session, from, to) {
230    list(balance,active_sessions)=get_prepaid_account_from_database();
231
232    if (count(active_sessions[from]) > 0) {
233        if (purge_expired_sessions()) {
234            // reload prepaid data
235            list(balance,active_sessions)=get_prepaid_account_from_database();
236        }
237
238        max=calculate_aggregated_maxsession_time(active_sessions[from],balance)
239        return max
240
241    } else {
242        // is the first session
243        rate = new Rate(session)         
244        active_sessions[from][]=session         
245        return rate->max_session_time()
246    }
247}
248
249calculate_aggregated_maxsession_time(active_sessions,balance)  {
250    // simulate session termination for all ongoing sessions
251    foreach (session in active_sessions[from]) {
252        due_balance=used_balance+show_price(session)
253    }
254
255    // calculate new virtual balance
256    balance_new=balance-due_balance
257
258    // simulate we start parallel sessions from scratch at this moment
259    // including the new sessionn setup request
260    // we skip any connect cost for session already in progress
261    active_sessions_new[from]=active_sessions[from]
262    active_sessions_new[from][]=session
263    foreach (session in active_sessions_new[from]) {
264        rate = new Rate(session)
265        maxsessiontime=rate->max_session_time()
266        // calculate price per second for each session
267        price_per_second=price_per_second+balance_new/maxsessiontime
268    }
269
270    return balance/price_per_second
271}
272
273debit_balance(session, from, to, duration) {
274    list(balance,active_sessions)=get_prepaid_account_from_database();
275    foreach (session in active_sessions[from]) {
276        if (session == session) continue
277        new_active_sessions[] = session
278    } 
279    // update list of active sessions
280    active_sessions[from]=new_active_sessions
281    price=showprice(session,from,to,duration)
282    balance=balance-price
283    update_prepaid_account_to_database(balance,active_sessions);
284    if (count(active_sessions[from]) > 0) {
285        max=calculate_aggregated_maxsession_time()
286    } else {
287        max=0
288    }
289    return max
290}
291
292
293Pseudo-code for session control engine
294--------------------------------------
295
296on_session_setup () {
297    max=cdrtool_max_session_time(session, from, to)
298    if (sip_connect_session() == true) {
299        // add session to the list of active sessions
300        // update tiomer again becuase we had a variable setup time     
301        max=cdrtool_max_session_time(session, from, to)
302        active_sessions[from][]=session
303        // set maxsession time for all remaining sessions of the same user
304        foreach (session in active_sessions[from]) {
305            session.maxsessiontime = max
306        }
307    }
308}
309
310on_session_disconnect () {
311   sip_disconnect_session();
312   max=cdrtool_debit_balance(session, from, to, duration)
313   // remove session from the list of active sessions
314   foreach (session in active_sessions[from]) {
315       if (session == session) continue
316       new_active_sessions[] = session
317   } 
318   // update list of active sessions
319   active_sessions[from]=new_active_sessions
320   foreach (session in active_sessions[from]) {
321       session.maxsessiontime = max
322   }
323}
Note: See TracBrowser for help on using the browser.