root/doc/PREPAID.txt

Revision 1228, 13.3 KB (checked in by Adrian Georgescu <ag@ag-projects.com>, 11 months ago)

Added ENUMTld to the API docs

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