mirror of https://github.com/asterisk/asterisk
Asterisk Generic AOC Representation - Generic AOC encode/decode routines. (Generic AOC must be encoded to be passed on the wire in the AST_CONTROL_AOC frame) - AST_CONTROL_AOC frame type to represent generic encoded AOC data - Manager events for AOC-S, AOC-D, and AOC-E messages Asterisk App Support - app_dial AOC-S pass-through support on call setup - app_queue AOC-S pass-through support on call setup AOC Unit Tests - AOC Unit Tests for encode/decode routines - AOC Unit Test for manager event representation. SIP AOC Support - Pass-through of generic AOC-D and AOC-E messages to snom phones via the snom AOC specification. - Creation of chan_sip page3 flags for the addition of the new 'snom_aoc_enabled' sip.conf option. IAX AOC Support - Natively supports AOC pass-through through the use of the new AST_CONTROL_AOC frame type DAHDI AOC Support - ETSI PRI full AOC Pass-through support - 'aoc_enable' chan_dahdi.conf option for independently enabling pass-through of AOC-S, AOC-D, AOC-E. - 'aoce_delayhangup' option for retrieving AOC-E on disconnect. - DAHDI A() dial string option for requesting AOC services. example usage: ;requests AOC-S, AOC-D, and AOC-E on call setup exten=>1111,1,Dial(DAHDI/g1/1112/A(s,d,e)) Review: https://reviewboard.asterisk.org/r/552/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@267096 65c4cc65-6c06-0410-ace0-fbb531ad65f3certified/1.8.6
parent
266db9fa8c
commit
afd4454c44
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,180 @@
|
||||
================
|
||||
Advice of Charge
|
||||
================
|
||||
|
||||
Written by: David Vossel
|
||||
Initial version: 04-19-2010
|
||||
|
||||
This document is designed to give an overview of how to configure and
|
||||
generate Advice of Charge along with a detailed explanation of how each
|
||||
option works.
|
||||
|
||||
--------------------------------------
|
||||
| Terminology |
|
||||
--------------------------------------
|
||||
AOC: Advice of Charge
|
||||
|
||||
AOC-S: Advice of Charge message sent at the beginning of a call during
|
||||
call setup. This message contains a list of rates associated with the
|
||||
call.
|
||||
|
||||
AOC-D: Advice of Charge message sent during the call. This message
|
||||
is typically used to update the endpoint with the current call charge.
|
||||
|
||||
AOC-E: Advice of Charge message sent at the end of a call. This
|
||||
message is used to indicate to the endpoint the final call charge.
|
||||
|
||||
AMI: Asterisk Manager Interface. This interface is used to generate
|
||||
AOC messages and listen for AOC events.
|
||||
|
||||
--------------------------------------
|
||||
| AOC in chan_dahdi |
|
||||
--------------------------------------
|
||||
----- LibPRI Support:
|
||||
ETSI, or euroisdn, is the only switchtype that LibPRI currently supports
|
||||
for AOC.
|
||||
|
||||
----- Enable AOC Pass-through in chan_dahdi
|
||||
To enable AOC pass-through between the ISDN and Asterisk use the
|
||||
'aoc_enable' config option. This option allows for any combination
|
||||
of AOC-S, AOC-D, and AOC-E to be enabled or disabled.
|
||||
|
||||
For example:
|
||||
aoc_enable=s,d,e ; enables pass-through of AOC-S, AOC-D, and AOC-E
|
||||
|
||||
aoc_enable=s,d ; enables pass-through of AOC-S and AOC-D. Rejects
|
||||
; AOC-E and AOC-E request messages
|
||||
|
||||
Since AOC messages are often transported on facility messages, the
|
||||
'facilityenable' option must be enabled as well to fully support AOC
|
||||
pass-through.
|
||||
|
||||
----- Handling AOC-E in chan_dahdi
|
||||
Whenever a dahdi channel receives an AOC-E message from Asterisk, it
|
||||
stores that message to deliver it at the appropriate time during call
|
||||
termination. This means that if two AOC-E messages are received on the
|
||||
same call, the last one will override the first one and only one AOC-E
|
||||
message will be sent during call termination.
|
||||
|
||||
There are some tricky situations involving the final AOC-E message. During
|
||||
a bridged call, if the endpoint receiving the AOC messages terminates
|
||||
the call before the endpoint delivering the AOC does, the final AOC-E
|
||||
message sent by the sending side during termination will never make it to
|
||||
the receiving end because Asterisk will have already torn down that channel.
|
||||
This is where the chan_dahdi.conf 'aoce_delayhangup' option comes into play.
|
||||
|
||||
By enabling 'aoce_delayhangup', anytime a hangup is initiated by the
|
||||
ISDN side of an Asterisk channel, instead of hanging up the channel,
|
||||
the channel sends a unique internal AOC-E termination request to its bridge
|
||||
channel. This indicates it is about to hangup and wishes to receive the
|
||||
final AOC-E message from the bridged channel before completely tearing
|
||||
down. If the bridged channel knows what to do with this AOC-E termination
|
||||
request, it will do whatever is necessary to indicate to its endpoint that
|
||||
the call is being terminated without actually hanging up the Asterisk channel.
|
||||
This allows the final AOC-E message to come in and be sent across the bridge
|
||||
while both channels are still up. If the channel delaying its hangup for
|
||||
the final AOC-E message times out, the call will be torn down just as it
|
||||
normally would. In chan_dahdi the timeout period is 1/2 the T305 timer
|
||||
which by default is 15 seconds.
|
||||
|
||||
'aoce_delayhangup' currently only works when both bridged channels are
|
||||
dahdi_channels. If a SIP channel receives an AOC-E termination request, it
|
||||
just responds by immediately hanging up the channel. Using this option when
|
||||
bridged to any channel technology besides SIP or DAHDI will result in the
|
||||
15 second timeout period before tearing down the call completely.
|
||||
|
||||
----- Requesting AOC services
|
||||
AOC can be requested on a call by call basis using the DAHDI dialstring
|
||||
option, A(). The A() option takes in 's', 'd', and 'e' parameters which
|
||||
represent the three types of AOC messages, AOC-S, AOC-D, and AOC-E. By using
|
||||
this option Asterisk will indicate to the endpoint during call setup that it
|
||||
wishes to receive the specified forms of AOC during the call.
|
||||
|
||||
Example Usage in extensions.conf
|
||||
exten => 1111,1,Dial(DAHDI/g1/1112/A(s,d,e) ; requests AOC-S, AOC-D, and AOC-E on
|
||||
; call setup
|
||||
exten => 1111,1,Dial(DAHDI/g1/1112/A(d,e) ; requests only AOC-D, and AOC-E on
|
||||
; call setup
|
||||
|
||||
--------------------------------------
|
||||
| AOC in chan_sip |
|
||||
--------------------------------------
|
||||
Asterisk supports a very basic way of sending AOC on a SIP channel to Snom
|
||||
phones using an AOC specification designed by Snom. This support is limited
|
||||
to the sending of AOC-D and AOC-E pass-through messages. No support for
|
||||
AOC-E on call termination is present, so if the Snom endpoint receiving the
|
||||
AOC messages from Asterisk terminates the call, the channel will be torn
|
||||
down before the phone can receive the final AOC-E message.
|
||||
|
||||
To enable passthrough of AOC messages via the snom specification, use
|
||||
the 'snom_aoc_enabled' option in sip.conf.
|
||||
|
||||
--------------------------------------
|
||||
| Generate AOC Messages via AMI |
|
||||
--------------------------------------
|
||||
Asterisk supports a way to generate AOC messages on a channel via
|
||||
the AMI action AOCMessage. At the moment the AOCMessage action is limited
|
||||
to AOC-D and AOC-E message generation. There are some limitations
|
||||
involved with delivering the final AOC-E message as well. The AOCMessage
|
||||
action has its own detailed parameter documentation so this discussion will
|
||||
focus on higher level use. When generating AOC messages on a Dahdi channel
|
||||
first make sure the appropriate chan_dahdi.conf options are enabled. Without
|
||||
enabling 'aoc_enable' correctly for pass-through the AOC messages will never
|
||||
make it out the pri. The same goes with SIP, the 'snom_aoc_enabled' option
|
||||
must be configured before messages can successfully be set to the endpoint.
|
||||
|
||||
----- AOC-D Message Generation
|
||||
AOC-D message generation can happen anytime throughout the call. This
|
||||
message type is very straight forward.
|
||||
|
||||
Example: AOCMessage action generating AOC-D currency message with Success
|
||||
response.
|
||||
|
||||
Action: AOCMessage
|
||||
Channel: DAHDI/i1/1111-1
|
||||
MsgType: d
|
||||
ChargeType: Currency
|
||||
CurrencyAmount: 16
|
||||
CurrencyName: USD
|
||||
CurrencyMultiplier: OneThousandth
|
||||
AOCBillingId: Normal
|
||||
ActionID: 1234
|
||||
|
||||
Response: Success
|
||||
ActionID: 1234
|
||||
Message: AOC Message successfully queued on channel
|
||||
|
||||
----- AOC-E Message Generation
|
||||
AOC-E messages are sent during call termination and represent the final charge
|
||||
total for the call. Since Asterisk call termination results in the channel
|
||||
being destroyed, it is currently not possible for the AOCMessage AMI action to
|
||||
be used to send the final AOC-E message on call hangup. There is however a
|
||||
work around for this issue that can be used for Dahdi channels. By default
|
||||
chan_dahdi saves any AOC-E message it receives from Asterisk during a call and
|
||||
waits to deliver that message during call termination. If multiple AOC-E messages
|
||||
are received from Asterisk on the same Dahdi channel, only the last message received
|
||||
is stored for delivery. This means that each new AOC-E message received on the
|
||||
channel overrides the previous one. Knowing this the final AOC-E message can be
|
||||
continually updated on a Dahdi channel until call termination occurs allowing
|
||||
the last update to be sent on hangup. This method is only as accurate as the
|
||||
intervals in which it is updated, but allows some form of AOC-E to be generated.
|
||||
|
||||
Example: AOCMessage action generating AOC-E unit message with Success response.
|
||||
|
||||
Action: AOCMessage
|
||||
Channel: DAHDI/i1/1111-1
|
||||
MsgType: e
|
||||
ChargeType: Unit
|
||||
UnitAmount(0): 111
|
||||
UnitType(0): 6
|
||||
UnitAmount(1): 222
|
||||
UnitType(1): 5
|
||||
UnitAmount(2): 333
|
||||
UnitType(3): 4
|
||||
UnitAmount(4): 444
|
||||
AOCBillingId: Normal
|
||||
ActionID: 1234
|
||||
|
||||
Response: Success
|
||||
ActionID: 1234
|
||||
Message: AOC Message successfully queued on channel
|
@ -0,0 +1,584 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* David Vossel <dvossel@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief Generic Advice of Charge encode and decode routines
|
||||
*
|
||||
* \author David Vossel <dvossel@digium.com>
|
||||
*/
|
||||
|
||||
#ifndef _AST_AOC_H_
|
||||
#define _AST_AOC_H_
|
||||
|
||||
#include "asterisk/channel.h"
|
||||
|
||||
#define AOC_CURRENCY_NAME_SIZE (10 + 1)
|
||||
|
||||
/*! \brief Defines the currency multiplier for an aoc message. */
|
||||
enum ast_aoc_currency_multiplier {
|
||||
AST_AOC_MULT_ONETHOUSANDTH = 1,
|
||||
AST_AOC_MULT_ONEHUNDREDTH,
|
||||
AST_AOC_MULT_ONETENTH,
|
||||
AST_AOC_MULT_ONE,
|
||||
AST_AOC_MULT_TEN,
|
||||
AST_AOC_MULT_HUNDRED,
|
||||
AST_AOC_MULT_THOUSAND,
|
||||
AST_AOC_MULT_NUM_ENTRIES, /* must remain the last item in enum, this is not a valid type */
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Defines the billing id options for an aoc message.
|
||||
* \note AOC-D is limited to NORMAL, REVERSE_CHARGE, and CREDIT_CARD.
|
||||
*/
|
||||
enum ast_aoc_billing_id {
|
||||
AST_AOC_BILLING_NA = 0,
|
||||
AST_AOC_BILLING_NORMAL,
|
||||
AST_AOC_BILLING_REVERSE_CHARGE,
|
||||
AST_AOC_BILLING_CREDIT_CARD,
|
||||
AST_AOC_BILLING_CALL_FWD_UNCONDITIONAL,
|
||||
AST_AOC_BILLING_CALL_FWD_BUSY,
|
||||
AST_AOC_BILLING_CALL_FWD_NO_REPLY,
|
||||
AST_AOC_BILLING_CALL_DEFLECTION,
|
||||
AST_AOC_BILLING_CALL_TRANSFER,
|
||||
AST_AOC_BILLING_NUM_ENTRIES /* must remain the last item in enum, not a valid billing id */
|
||||
};
|
||||
|
||||
enum ast_aoc_type {
|
||||
AST_AOC_REQUEST = 0,
|
||||
AST_AOC_S,
|
||||
AST_AOC_D,
|
||||
AST_AOC_E, /* aoc-e must remain the last item in this enum */
|
||||
};
|
||||
|
||||
enum ast_aoc_charge_type {
|
||||
AST_AOC_CHARGE_NA = 0,
|
||||
AST_AOC_CHARGE_FREE,
|
||||
AST_AOC_CHARGE_CURRENCY,
|
||||
AST_AOC_CHARGE_UNIT, /* unit must remain the last item in enum */
|
||||
};
|
||||
|
||||
enum ast_aoc_request {
|
||||
AST_AOC_REQUEST_S = (1 << 0),
|
||||
AST_AOC_REQUEST_D = (1 << 1),
|
||||
AST_AOC_REQUEST_E = (1 << 2),
|
||||
};
|
||||
|
||||
enum ast_aoc_total_type {
|
||||
AST_AOC_TOTAL = 0,
|
||||
AST_AOC_SUBTOTAL = 1,
|
||||
};
|
||||
|
||||
enum ast_aoc_time_scale {
|
||||
AST_AOC_TIME_SCALE_HUNDREDTH_SECOND,
|
||||
AST_AOC_TIME_SCALE_TENTH_SECOND,
|
||||
AST_AOC_TIME_SCALE_SECOND,
|
||||
AST_AOC_TIME_SCALE_TEN_SECOND,
|
||||
AST_AOC_TIME_SCALE_MINUTE,
|
||||
AST_AOC_TIME_SCALE_HOUR,
|
||||
AST_AOC_TIME_SCALE_DAY,
|
||||
};
|
||||
|
||||
struct ast_aoc_time {
|
||||
/*! LengthOfTimeUnit (Not valid if length is zero.) */
|
||||
uint32_t length;
|
||||
uint16_t scale;
|
||||
};
|
||||
|
||||
struct ast_aoc_duration_rate {
|
||||
uint32_t amount;
|
||||
uint32_t time;
|
||||
/*! Not present if the granularity time is zero. */
|
||||
uint32_t granularity_time;
|
||||
|
||||
uint16_t multiplier;
|
||||
uint16_t time_scale;
|
||||
uint16_t granularity_time_scale;
|
||||
|
||||
/*! Name of currency involved. Null terminated. */
|
||||
char currency_name[AOC_CURRENCY_NAME_SIZE];
|
||||
|
||||
/*!
|
||||
* \brief Charging interval type
|
||||
* \details
|
||||
* continuousCharging(0),
|
||||
* stepFunction(1)
|
||||
*/
|
||||
uint8_t charging_type;
|
||||
};
|
||||
|
||||
enum ast_aoc_volume_unit {
|
||||
AST_AOC_VOLUME_UNIT_OCTET,
|
||||
AST_AOC_VOLUME_UNIT_SEGMENT,
|
||||
AST_AOC_VOLUME_UNIT_MESSAGE,
|
||||
};
|
||||
|
||||
struct ast_aoc_volume_rate {
|
||||
uint32_t amount;
|
||||
uint16_t multiplier;
|
||||
uint16_t volume_unit;
|
||||
char currency_name[AOC_CURRENCY_NAME_SIZE];
|
||||
};
|
||||
|
||||
struct ast_aoc_flat_rate {
|
||||
uint32_t amount;
|
||||
uint16_t multiplier;
|
||||
/*! Name of currency involved. Null terminated. */
|
||||
char currency_name[AOC_CURRENCY_NAME_SIZE];
|
||||
};
|
||||
|
||||
enum ast_aoc_s_charged_item {
|
||||
AST_AOC_CHARGED_ITEM_NA,
|
||||
AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT,
|
||||
AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION,
|
||||
AST_AOC_CHARGED_ITEM_CALL_ATTEMPT,
|
||||
AST_AOC_CHARGED_ITEM_CALL_SETUP,
|
||||
AST_AOC_CHARGED_ITEM_USER_USER_INFO,
|
||||
AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE,
|
||||
};
|
||||
|
||||
enum ast_aoc_s_rate_type {
|
||||
AST_AOC_RATE_TYPE_NA,
|
||||
AST_AOC_RATE_TYPE_FREE,
|
||||
AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING,
|
||||
AST_AOC_RATE_TYPE_DURATION,
|
||||
AST_AOC_RATE_TYPE_FLAT,
|
||||
AST_AOC_RATE_TYPE_VOLUME,
|
||||
AST_AOC_RATE_TYPE_SPECIAL_CODE,
|
||||
};
|
||||
|
||||
struct ast_aoc_s_entry {
|
||||
uint16_t charged_item;
|
||||
uint16_t rate_type;
|
||||
|
||||
/*! \brief Charge rate being applied. */
|
||||
union {
|
||||
struct ast_aoc_duration_rate duration;
|
||||
struct ast_aoc_flat_rate flat;
|
||||
struct ast_aoc_volume_rate volume;
|
||||
uint16_t special_code; /* 1...10 */
|
||||
} rate;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ast_aoc_unit_entry {
|
||||
char valid_amount;
|
||||
unsigned int amount;
|
||||
char valid_type;
|
||||
unsigned int type; /* 1 - 16 by ETSI standard */
|
||||
};
|
||||
|
||||
enum AST_AOC_CHARGING_ASSOCIATION {
|
||||
AST_AOC_CHARGING_ASSOCIATION_NA,
|
||||
AST_AOC_CHARGING_ASSOCIATION_NUMBER,
|
||||
AST_AOC_CHARGING_ASSOCIATION_ID,
|
||||
};
|
||||
struct ast_aoc_charging_association_number {
|
||||
uint8_t plan;
|
||||
char number[32];
|
||||
} __attribute__((packed));
|
||||
struct ast_aoc_charging_association {
|
||||
union {
|
||||
int32_t id;
|
||||
struct ast_aoc_charging_association_number number;
|
||||
} charge;
|
||||
/*! \see enum AST_AOC_CHARGING_ASSOCIATION */
|
||||
uint8_t charging_type;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*! \brief AOC Payload Header. Holds all the encoded AOC data to pass on the wire */
|
||||
struct ast_aoc_encoded;
|
||||
|
||||
/*! \brief Decoded AOC data. This value is used to set all the values in an AOC message before encoding.*/
|
||||
struct ast_aoc_decoded;
|
||||
|
||||
/*!
|
||||
* \brief creates a ast_aoc_decode object of a specific message type
|
||||
* \since 1.8
|
||||
*
|
||||
* \param msg_type AOC-D, AOC-E, or AOC Request
|
||||
* \param charge_type this is ignored if message type is not AOC-D or AOC-E.
|
||||
* \param requests flags. This defines the types of AOC requested. This
|
||||
* field should only be set when the message type is AOC Request,
|
||||
* the value is ignored otherwise.
|
||||
*
|
||||
* \retval heap allocated ast_aoc_decoded object ptr on success
|
||||
* \retval NULL failure
|
||||
*/
|
||||
struct ast_aoc_decoded *ast_aoc_create(const enum ast_aoc_type msg_type,
|
||||
const enum ast_aoc_charge_type charge_type,
|
||||
const enum ast_aoc_request requests);
|
||||
|
||||
|
||||
/*! \brief free an ast_aoc_decoded object */
|
||||
void *ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded);
|
||||
|
||||
/*! \brief free an ast_aoc_encoded object */
|
||||
void *ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded);
|
||||
|
||||
/*!
|
||||
* \brief decodes an encoded aoc payload.
|
||||
* \since 1.8
|
||||
*
|
||||
* \param encoded the encoded payload to decode.
|
||||
* \param size total size of encoded payload
|
||||
* \param chan ast channel, Optional for DEBUG output purposes
|
||||
*
|
||||
* \retval heap allocated ast_aoc_decoded object ptr on success
|
||||
* \retval NULL failure
|
||||
*/
|
||||
struct ast_aoc_decoded *ast_aoc_decode(struct ast_aoc_encoded *encoded, size_t size, struct ast_channel *chan);
|
||||
|
||||
/*!
|
||||
* \brief encodes a decoded aoc structure so it can be passed on the wire
|
||||
* \since 1.8
|
||||
*
|
||||
* \param decoded the decoded struct to be encoded
|
||||
* \param out_size output parameter representing size of encoded data
|
||||
* \param chan ast channel, Optional for DEBUG output purposes
|
||||
*
|
||||
* \retval pointer to encoded data
|
||||
* \retval NULL failure
|
||||
*/
|
||||
struct ast_aoc_encoded *ast_aoc_encode(struct ast_aoc_decoded *decoded, size_t *out_size, struct ast_channel *chan);
|
||||
|
||||
/*!
|
||||
* \brief Sets the type of total for a AOC-D message
|
||||
* \since 1.8
|
||||
*
|
||||
* \param decoded ast_aoc_decoded struct to set values on
|
||||
* \param type total type: TOTAL or SUBTOTAL
|
||||
*
|
||||
* \note If this value is not set, the default for the message is TOTAL
|
||||
*
|
||||
* \retval 0 success
|
||||
*/
|
||||
int ast_aoc_set_total_type(struct ast_aoc_decoded *decoded, const enum ast_aoc_total_type type);
|
||||
|
||||
/*!
|
||||
* \brief Sets the currency values for a AOC-D or AOC-E message
|
||||
* \since 1.8
|
||||
*
|
||||
* \param decoded ast_aoc_decoded struct to set values on
|
||||
* \param amount currency amount REQUIRED
|
||||
* \param multiplier currency multiplier REQUIRED, 0 or undefined value defaults to AST_AOC_MULT_ONE.
|
||||
* \param name currency name OPTIONAL
|
||||
*
|
||||
* \retval 0 success
|
||||
*/
|
||||
int ast_aoc_set_currency_info(struct ast_aoc_decoded *decoded,
|
||||
const unsigned int amount,
|
||||
const enum ast_aoc_currency_multiplier multiplier,
|
||||
const char *name);
|
||||
|
||||
/*!
|
||||
* \brief Adds a unit entry into the list of units
|
||||
* \since 1.8
|
||||
*
|
||||
* \param decoded ast_aoc_decoded struct to set values on
|
||||
* \param amount_is_present set this if the number of units is actually present.
|
||||
* \param amount number of units
|
||||
* \param type_is_present set this if the type value is present
|
||||
* \param type unit type
|
||||
*
|
||||
* \note If neither the amount nor the type is present, the entry will
|
||||
* not be added.
|
||||
*
|
||||
* \retval 0 success
|
||||
*/
|
||||
int ast_aoc_add_unit_entry(struct ast_aoc_decoded *decoded,
|
||||
const unsigned int amount_is_present,
|
||||
const unsigned int amount,
|
||||
const unsigned int type_is_present,
|
||||
const unsigned int type);
|
||||
|
||||
/*!
|
||||
* \brief set the billing id for a AOC-D or AST_AOC_E message
|
||||
* \since 1.8
|
||||
*
|
||||
* \param decoded ast_aoc_decoded struct to set values on
|
||||
* \param id billing id
|
||||
*
|
||||
* \retval 0 success
|
||||
*/
|
||||
int ast_aoc_set_billing_id(struct ast_aoc_decoded *decoded, const enum ast_aoc_billing_id id);
|
||||
|
||||
/*!
|
||||
* \brief set the charging association id for an AST_AOC_E message
|
||||
* \since 1.8
|
||||
*
|
||||
* \param decoded ast_aoc_decoded struct to set values on
|
||||
* \param id charging association identifier
|
||||
*
|
||||
* \note If the association number was set, this will override that value. Only the id OR the
|
||||
* number can be set at a time, not both.
|
||||
*
|
||||
* \retval 0 success
|
||||
*/
|
||||
int ast_aoc_set_association_id(struct ast_aoc_decoded *decoded, const int id);
|
||||
|
||||
/*!
|
||||
* \brief set the charging accociation number for an AOC-E message
|
||||
* \since 1.8
|
||||
*
|
||||
* \param decoded ast_aoc_decoded struct to set values on
|
||||
* \param num charging association number
|
||||
* \param plan charging association number plan and type-of-number fields
|
||||
*
|
||||
* \note If the association id was set, this will override that value. Only the id OR the
|
||||
* number can be set at a time, not both.
|
||||
*
|
||||
* \retval 0 success
|
||||
*/
|
||||
int ast_aoc_set_association_number(struct ast_aoc_decoded *decoded, const char *num, uint8_t plan);
|
||||
|
||||
/*!
|
||||
* \brief Mark the AST_AOC_REQUEST message as a termination request.
|
||||
* \since 1.8
|
||||
*
|
||||
* \param decoded ast_aoc_decoded struct to set values on
|
||||
*
|
||||
* \note A termination request indicates that the call has terminated,
|
||||
* but that the other side is waiting for a short period of time before
|
||||
* hanging up so it can get the final AOC-E message.
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int ast_aoc_set_termination_request(struct ast_aoc_decoded *decoded);
|
||||
|
||||
/*!
|
||||
* \brief Add AOC-S duration rate entry
|
||||
* \since 1.8
|
||||
*
|
||||
* \param decoded aoc decoded object to add entry to
|
||||
* \param charged_item ast_aoc_s_charged_item
|
||||
* \param amount currency amount
|
||||
* \param multiplier currency multiplier
|
||||
* \param currency_name truncated after 10 characters
|
||||
* \param time
|
||||
* \param time_scale from ast_aoc_time_scale enum
|
||||
* \param granularity_time (optional, set to 0 if not present);
|
||||
* \param granularity_time_scale (optional, set to 0 if not present);
|
||||
* \param step_function set to 1 if this is to use a step function, 0 if continuious
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int ast_aoc_s_add_rate_duration(struct ast_aoc_decoded *decoded,
|
||||
enum ast_aoc_s_charged_item charged_item,
|
||||
unsigned int amount,
|
||||
enum ast_aoc_currency_multiplier multiplier,
|
||||
const char *currency_name,
|
||||
unsigned long time,
|
||||
enum ast_aoc_time_scale time_scale,
|
||||
unsigned long granularity_time,
|
||||
enum ast_aoc_time_scale granularity_time_scale,
|
||||
int step_function);
|
||||
|
||||
/*!
|
||||
* \brief Add AOC-S flat rate entry
|
||||
* \since 1.8
|
||||
*
|
||||
* \param decoded aoc decoded object to add entry to
|
||||
* \param charged_item ast_aoc_s_charged_item
|
||||
* \param amount currency amount
|
||||
* \param multiplier currency multiplier
|
||||
* \param currency_name truncated after 10 characters
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int ast_aoc_s_add_rate_flat(struct ast_aoc_decoded *decoded,
|
||||
enum ast_aoc_s_charged_item charged_item,
|
||||
unsigned int amount,
|
||||
enum ast_aoc_currency_multiplier multiplier,
|
||||
const char *currency_name);
|
||||
|
||||
/*!
|
||||
* \brief Add AOC-S volume rate entry
|
||||
* \since 1.8
|
||||
*
|
||||
* \param decoded aoc decoded object to add entry to
|
||||
* \param charged_item ast_aoc_s_charged_item
|
||||
* \param volume_unit from ast_aoc_volume_unit enum
|
||||
* \param amount currency amount
|
||||
* \param multiplier currency multiplier
|
||||
* \param currency_name truncated after 10 characters
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int ast_aoc_s_add_rate_volume(struct ast_aoc_decoded *decoded,
|
||||
enum ast_aoc_s_charged_item charged_item,
|
||||
enum ast_aoc_volume_unit volume_unit,
|
||||
unsigned int amount,
|
||||
enum ast_aoc_currency_multiplier multiplier,
|
||||
const char *currency_name);
|
||||
|
||||
/*!
|
||||
* \brief Add AOC-S special rate entry
|
||||
* \since 1.8
|
||||
*
|
||||
* \param decoded aoc decoded object to add entry to
|
||||
* \param charged_item ast_aoc_s_charged_item
|
||||
* \param code special charging code
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int ast_aoc_s_add_rate_special_charge_code(struct ast_aoc_decoded *decoded,
|
||||
enum ast_aoc_s_charged_item charged_item,
|
||||
unsigned int code);
|
||||
|
||||
/*!
|
||||
* \brief Add AOC-S indicating charge item is free
|
||||
* \since 1.8
|
||||
*
|
||||
* \param decoded aoc decoded object to add entry to
|
||||
* \param charged_item ast_aoc_s_charged_item
|
||||
* \param from_beginning TRUE if the rate is free from beginning.
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int ast_aoc_s_add_rate_free(struct ast_aoc_decoded *decoded,
|
||||
enum ast_aoc_s_charged_item charged_item, int from_beginning);
|
||||
|
||||
/*!
|
||||
* \brief Add AOC-S entry indicating charge item is not available
|
||||
* \since 1.8
|
||||
*
|
||||
* \param decoded aoc decoded object to add entry to
|
||||
* \param charged_item ast_aoc_s_charged_item
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int ast_aoc_s_add_rate_na(struct ast_aoc_decoded *decoded,
|
||||
enum ast_aoc_s_charged_item charged_item);
|
||||
|
||||
/*!
|
||||
* \brief Add AOC-S special arrangement entry
|
||||
* \since 1.8
|
||||
*
|
||||
* \param decoded aoc decoded object to add entry to
|
||||
* \param code special arrangement code
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int ast_aoc_s_add_special_arrangement(struct ast_aoc_decoded *decoded,
|
||||
unsigned int code);
|
||||
|
||||
/*!
|
||||
* \brief Convert decoded aoc msg to string representation
|
||||
* \since 1.8
|
||||
*
|
||||
* \param decoded ast_aoc_decoded struct to convert to string
|
||||
* \param msg dynamic heap allocated ast_str object to store string representation in
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int ast_aoc_decoded2str(const struct ast_aoc_decoded *decoded, struct ast_str **msg);
|
||||
|
||||
/*! \brief generate AOC manager event for an AOC-S, AOC-D, or AOC-E msg */
|
||||
int ast_aoc_manager_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan);
|
||||
|
||||
/*! \brief get the message type, AOC-D, AOC-E, or AOC Request */
|
||||
enum ast_aoc_type ast_aoc_get_msg_type(struct ast_aoc_decoded *decoded);
|
||||
|
||||
/*! \brief get the charging type for an AOC-D or AOC-E message */
|
||||
enum ast_aoc_charge_type ast_aoc_get_charge_type(struct ast_aoc_decoded *decoded);
|
||||
|
||||
/*! \brief get the types of AOC requested for when message type is AOC Request */
|
||||
enum ast_aoc_request ast_aoc_get_request(struct ast_aoc_decoded *decoded);
|
||||
|
||||
/*! \brief get the type of total for a AOC-D message */
|
||||
enum ast_aoc_total_type ast_aoc_get_total_type(struct ast_aoc_decoded *decoded);
|
||||
|
||||
/*! \brief get the currency amount for AOC-D and AOC-E messages*/
|
||||
unsigned int ast_aoc_get_currency_amount(struct ast_aoc_decoded *decoded);
|
||||
|
||||
/*! \brief get the number rates associated with an AOC-S message */
|
||||
unsigned int ast_aoc_s_get_count(struct ast_aoc_decoded *decoded);
|
||||
|
||||
/*!
|
||||
* \brief get a specific AOC-S rate entry.
|
||||
* \since 1.8
|
||||
*
|
||||
* \note This can be used in conjunction with ast_aoc_s_get_count to create
|
||||
* a unit entry iterator.
|
||||
*/
|
||||
const struct ast_aoc_s_entry *ast_aoc_s_get_rate_info(struct ast_aoc_decoded *decoded, unsigned int entry_number);
|
||||
|
||||
/*! \brief get the number of unit entries for AOC-D and AOC-E messages*/
|
||||
unsigned int ast_aoc_get_unit_count(struct ast_aoc_decoded *decoded);
|
||||
|
||||
/*!
|
||||
* \brief get a specific unit entry.
|
||||
* \since 1.8
|
||||
*
|
||||
* \note This can be used in conjunction with ast_aoc_get_unit_count to create
|
||||
* a unit entry iterator.
|
||||
*/
|
||||
const struct ast_aoc_unit_entry *ast_aoc_get_unit_info(struct ast_aoc_decoded *decoded, unsigned int entry_number);
|
||||
|
||||
/*! \brief get the currency multiplier for AOC-D and AOC-E messages */
|
||||
enum ast_aoc_currency_multiplier ast_aoc_get_currency_multiplier(struct ast_aoc_decoded *decoded);
|
||||
|
||||
/*! \brief get the currency multiplier for AOC-D and AOC-E messages in decimal format */
|
||||
const char *ast_aoc_get_currency_multiplier_decimal(struct ast_aoc_decoded *decoded);
|
||||
|
||||
/*! \brief get the currency name for AOC-D and AOC-E messages*/
|
||||
const char *ast_aoc_get_currency_name(struct ast_aoc_decoded *decoded);
|
||||
|
||||
/*! \brief get the billing id for AOC-D and AOC-E messages*/
|
||||
enum ast_aoc_billing_id ast_aoc_get_billing_id(struct ast_aoc_decoded *decoded);
|
||||
|
||||
/*! \brief get the charging association info for AOC-E messages*/
|
||||
const struct ast_aoc_charging_association *ast_aoc_get_association_info(struct ast_aoc_decoded *decoded);
|
||||
|
||||
/*!
|
||||
* \brief get whether or not the AST_AOC_REQUEST message as a termination request.
|
||||
* \since 1.8
|
||||
*
|
||||
* \note a termination request indicates that the call has terminated,
|
||||
* but that the other side is waiting for a short period of time
|
||||
* before hanging up so it can get the final AOC-E message.
|
||||
*
|
||||
* \param decoded ast_aoc_decoded struct to get values on
|
||||
*
|
||||
* \retval 0 not a termination request
|
||||
* \retval 1 is a termination request
|
||||
*/
|
||||
int ast_aoc_get_termination_request(struct ast_aoc_decoded *decoded);
|
||||
|
||||
/*!
|
||||
* \brief test aoc encode decode routines.
|
||||
* \since 1.8
|
||||
*
|
||||
* \note This function verifies that a decoded message matches itself after
|
||||
* the encode decode routine.
|
||||
*/
|
||||
int ast_aoc_test_encode_decode_match(struct ast_aoc_decoded *decoded);
|
||||
|
||||
/*! \brief enable aoc cli options */
|
||||
int ast_aoc_cli_init(void);
|
||||
|
||||
#endif /* _AST_AOC_H_ */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,690 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* David Vossel <dvossel@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief Generic AOC encode decode tests
|
||||
*
|
||||
* \author David Vossel <dvossel@digium.com>
|
||||
*
|
||||
* \ingroup tests
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<depend>TEST_FRAMEWORK</depend>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/test.h"
|
||||
#include "asterisk/aoc.h"
|
||||
|
||||
|
||||
AST_TEST_DEFINE(aoc_event_generation_test)
|
||||
{
|
||||
int res = AST_TEST_PASS;
|
||||
struct ast_aoc_decoded *decoded = NULL;
|
||||
struct ast_str *msg = NULL;
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "aoc_event_test";
|
||||
info->category = "main/aoc/";
|
||||
info->summary = "Advice of Charge event generation test";
|
||||
info->description =
|
||||
"Creates AOC messages, verify event string matches expected results";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(msg = ast_str_create(1024))) {
|
||||
goto cleanup_aoc_event_test;
|
||||
}
|
||||
|
||||
/* ---- TEST 1, AOC-D event generation */
|
||||
if (!(decoded = ast_aoc_create(AST_AOC_D, AST_AOC_CHARGE_CURRENCY, 0))) {
|
||||
|
||||
ast_test_status_update(test, "failed to create AOC-D message for event generation.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_event_test;
|
||||
}
|
||||
/* Add billing id information */
|
||||
ast_aoc_set_billing_id(decoded, AST_AOC_BILLING_CREDIT_CARD);
|
||||
|
||||
/* Set currency information, verify results */
|
||||
if ((ast_aoc_set_currency_info(decoded, 100, AST_AOC_MULT_ONE, "usd")) ||
|
||||
(ast_aoc_set_total_type(decoded, AST_AOC_SUBTOTAL))) {
|
||||
|
||||
ast_test_status_update(test, "failed to set currency info in AOC-D msg\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_event_test;
|
||||
}
|
||||
if (ast_aoc_decoded2str(decoded, &msg)) {
|
||||
|
||||
ast_test_status_update(test, "failed to generate AOC-D msg string.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_event_test;
|
||||
}
|
||||
if (strncmp(ast_str_buffer(msg),
|
||||
"AOC-D\r\n"
|
||||
"Type: Currency\r\n"
|
||||
"BillingID: CreditCard\r\n"
|
||||
"TypeOfCharging: SubTotal\r\n"
|
||||
"Currency: usd\r\n"
|
||||
"Currency/Amount/Cost: 100\r\n"
|
||||
"Currency/Amount/Multiplier: 1\r\n",
|
||||
strlen(ast_str_buffer(msg)))) {
|
||||
|
||||
ast_test_status_update(test, "AOC-D msg event did not match expected results\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_event_test;
|
||||
}
|
||||
decoded = ast_aoc_destroy_decoded(decoded);
|
||||
ast_str_reset(msg);
|
||||
|
||||
|
||||
/* ---- TEST 2, AOC-S event generation */
|
||||
if (!(decoded = ast_aoc_create(AST_AOC_S, 0, 0))) {
|
||||
ast_test_status_update(test, "failed to create AOC-S message for event generation.\n");
|
||||
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_event_test;
|
||||
}
|
||||
|
||||
ast_aoc_s_add_rate_flat(decoded,
|
||||
AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION,
|
||||
123,
|
||||
AST_AOC_MULT_TEN,
|
||||
"pineapple");
|
||||
|
||||
ast_aoc_s_add_rate_volume(decoded,
|
||||
AST_AOC_CHARGED_ITEM_CALL_ATTEMPT,
|
||||
AST_AOC_VOLUME_UNIT_SEGMENT,
|
||||
937,
|
||||
AST_AOC_MULT_ONEHUNDREDTH,
|
||||
"oranges");
|
||||
|
||||
ast_aoc_s_add_rate_duration(decoded,
|
||||
AST_AOC_CHARGED_ITEM_CALL_ATTEMPT,
|
||||
937,
|
||||
AST_AOC_MULT_ONETHOUSANDTH,
|
||||
"bananas",
|
||||
848,
|
||||
AST_AOC_TIME_SCALE_TENTH_SECOND,
|
||||
949,
|
||||
AST_AOC_TIME_SCALE_HOUR,
|
||||
1);
|
||||
|
||||
ast_aoc_s_add_rate_duration(decoded,
|
||||
AST_AOC_CHARGED_ITEM_USER_USER_INFO,
|
||||
937,
|
||||
AST_AOC_MULT_THOUSAND,
|
||||
"bananas",
|
||||
1111,
|
||||
AST_AOC_TIME_SCALE_SECOND,
|
||||
2222,
|
||||
AST_AOC_TIME_SCALE_DAY,
|
||||
0);
|
||||
|
||||
if (ast_aoc_decoded2str(decoded, &msg)) {
|
||||
|
||||
ast_test_status_update(test, "failed to generate AOC-D msg string.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_event_test;
|
||||
}
|
||||
|
||||
|
||||
if (strncmp(ast_str_buffer(msg),
|
||||
"AOC-S\r\n"
|
||||
"NumberRates: 4\r\n"
|
||||
"Rate(0)/Chargeable: BasicCommunication\r\n"
|
||||
"Rate(0)/Type: Flat\r\n"
|
||||
"Rate(0)/Flat/Currency: pineapple\r\n"
|
||||
"Rate(0)/Flat/Amount/Cost: 123\r\n"
|
||||
"Rate(0)/Flat/Amount/Multiplier: 10\r\n"
|
||||
"Rate(1)/Chargeable: CallAttempt\r\n"
|
||||
"Rate(1)/Type: Volume\r\n"
|
||||
"Rate(1)/Volume/Currency: oranges\r\n"
|
||||
"Rate(1)/Volume/Amount/Cost: 937\r\n"
|
||||
"Rate(1)/Volume/Amount/Multiplier: 1/100\r\n"
|
||||
"Rate(1)/Volume/Unit: Segment\r\n"
|
||||
"Rate(2)/Chargeable: CallAttempt\r\n"
|
||||
"Rate(2)/Type: Duration\r\n"
|
||||
"Rate(2)/Duration/Currency: bananas\r\n"
|
||||
"Rate(2)/Duration/Amount/Cost: 937\r\n"
|
||||
"Rate(2)/Duration/Amount/Multiplier: 1/1000\r\n"
|
||||
"Rate(2)/Duration/ChargingType: StepFunction\r\n"
|
||||
"Rate(2)/Duration/Time/Length: 848\r\n"
|
||||
"Rate(2)/Duration/Time/Scale: OneTenthSecond\r\n"
|
||||
"Rate(2)/Duration/Granularity/Length: 949\r\n"
|
||||
"Rate(2)/Duration/Granularity/Scale: Hour\r\n"
|
||||
"Rate(3)/Chargeable: UserUserInfo\r\n"
|
||||
"Rate(3)/Type: Duration\r\n"
|
||||
"Rate(3)/Duration/Currency: bananas\r\n"
|
||||
"Rate(3)/Duration/Amount/Cost: 937\r\n"
|
||||
"Rate(3)/Duration/Amount/Multiplier: 1000\r\n"
|
||||
"Rate(3)/Duration/ChargingType: ContinuousCharging\r\n"
|
||||
"Rate(3)/Duration/Time/Length: 1111\r\n"
|
||||
"Rate(3)/Duration/Time/Scale: Second\r\n"
|
||||
"Rate(3)/Duration/Granularity/Length: 2222\r\n"
|
||||
"Rate(3)/Duration/Granularity/Scale: Day\r\n",
|
||||
strlen(ast_str_buffer(msg)))) {
|
||||
|
||||
ast_test_status_update(test, "AOC-S msg event did not match expected results\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_event_test;
|
||||
}
|
||||
decoded = ast_aoc_destroy_decoded(decoded);
|
||||
ast_str_reset(msg);
|
||||
|
||||
/* ---- TEST 3, AOC-E event generation with various charging association information*/
|
||||
if (!(decoded = ast_aoc_create(AST_AOC_E, AST_AOC_CHARGE_UNIT, 0))) {
|
||||
ast_test_status_update(test, "failed to create AOC-E message for event generation.\n");
|
||||
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_event_test;
|
||||
}
|
||||
if ((ast_aoc_add_unit_entry(decoded, 1, 111, 1, 1)) ||
|
||||
(!ast_aoc_add_unit_entry(decoded, 0, 2222, 0, 2)) || /* we expect this to fail, and it should not be added to entry list */
|
||||
(ast_aoc_add_unit_entry(decoded, 1, 3333, 0, 3)) ||
|
||||
(ast_aoc_add_unit_entry(decoded, 0, 44444, 1, 4))) {
|
||||
|
||||
ast_test_status_update(test, "failed to set unit info for AOC-E message\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_event_test;
|
||||
}
|
||||
|
||||
if (ast_aoc_decoded2str(decoded, &msg)) {
|
||||
ast_test_status_update(test, "failed to generate AOC-E msg string.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_event_test;
|
||||
}
|
||||
|
||||
if (strncmp(ast_str_buffer(msg),
|
||||
"AOC-E\r\n"
|
||||
"Type: Units\r\n"
|
||||
"BillingID: NotAvailable\r\n"
|
||||
"Units/NumberItems: 3\r\n"
|
||||
"Units/Item(0)/NumberOf: 111\r\n"
|
||||
"Units/Item(0)/TypeOf: 1\r\n"
|
||||
"Units/Item(1)/NumberOf: 3333\r\n"
|
||||
"Units/Item(2)/TypeOf: 4\r\n",
|
||||
strlen(ast_str_buffer(msg)))) {
|
||||
|
||||
ast_test_status_update(test, "AOC-E msg event did not match expected results, with no charging association info\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_event_test;
|
||||
}
|
||||
|
||||
/* add AOC-E charging association number info */
|
||||
if (ast_aoc_set_association_number(decoded, "555-555-5555", 16)) {
|
||||
ast_test_status_update(test, "failed to set the charging association number info correctly, 3\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_event_test;
|
||||
}
|
||||
|
||||
ast_str_reset(msg);
|
||||
if (ast_aoc_decoded2str(decoded, &msg)) {
|
||||
ast_test_status_update(test, "failed to generate AOC-E msg string.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_event_test;
|
||||
}
|
||||
|
||||
if (strncmp(ast_str_buffer(msg),
|
||||
"AOC-E\r\n"
|
||||
"ChargingAssociation/Number: 555-555-5555\r\n"
|
||||
"ChargingAssociation/Number/Plan: 16\r\n"
|
||||
"Type: Units\r\n"
|
||||
"BillingID: NotAvailable\r\n"
|
||||
"Units/NumberItems: 3\r\n"
|
||||
"Units/Item(0)/NumberOf: 111\r\n"
|
||||
"Units/Item(0)/TypeOf: 1\r\n"
|
||||
"Units/Item(1)/NumberOf: 3333\r\n"
|
||||
"Units/Item(2)/TypeOf: 4\r\n",
|
||||
strlen(ast_str_buffer(msg)))) {
|
||||
|
||||
ast_test_status_update(test, "AOC-E msg event did not match expected results, with charging association number\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_event_test;
|
||||
}
|
||||
|
||||
/* add AOC-E charging association id info */
|
||||
if (ast_aoc_set_association_id(decoded, 2222)) {
|
||||
ast_test_status_update(test, "failed to set the charging association number info correctly, 3\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_event_test;
|
||||
}
|
||||
|
||||
ast_str_reset(msg);
|
||||
if (ast_aoc_decoded2str(decoded, &msg)) {
|
||||
ast_test_status_update(test, "failed to generate AOC-E msg string.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_event_test;
|
||||
}
|
||||
|
||||
if (strncmp(ast_str_buffer(msg),
|
||||
"AOC-E\r\n"
|
||||
"ChargingAssociation/ID: 2222\r\n"
|
||||
"Type: Units\r\n"
|
||||
"BillingID: NotAvailable\r\n"
|
||||
"Units/NumberItems: 3\r\n"
|
||||
"Units/Item(0)/NumberOf: 111\r\n"
|
||||
"Units/Item(0)/TypeOf: 1\r\n"
|
||||
"Units/Item(1)/NumberOf: 3333\r\n"
|
||||
"Units/Item(2)/TypeOf: 4\r\n",
|
||||
strlen(ast_str_buffer(msg)))) {
|
||||
|
||||
ast_test_status_update(test, "AOC-E msg event did not match expected results with charging association id.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_event_test;
|
||||
}
|
||||
|
||||
|
||||
cleanup_aoc_event_test:
|
||||
|
||||
decoded = ast_aoc_destroy_decoded(decoded);
|
||||
ast_free(msg);
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_TEST_DEFINE(aoc_encode_decode_test)
|
||||
{
|
||||
int res = AST_TEST_PASS;
|
||||
struct ast_aoc_decoded *decoded;
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "aoc_encode_decode_test";
|
||||
info->category = "main/aoc/";
|
||||
info->summary = "Advice of Charge encode and decode test";
|
||||
info->description =
|
||||
"This tests the Advice of Charge encode and decode routines.";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
/* ---- Test 1 ---- create AOC-D message, encode message, and decode message once again. */
|
||||
/* create AOC-D message */
|
||||
if (!(decoded = ast_aoc_create(AST_AOC_D, AST_AOC_CHARGE_CURRENCY, 0)) ||
|
||||
(ast_aoc_get_msg_type(decoded) != AST_AOC_D) ||
|
||||
(ast_aoc_get_charge_type(decoded) != AST_AOC_CHARGE_CURRENCY)) {
|
||||
|
||||
ast_test_status_update(test, "Test 1: failed to create AOC-D message\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
|
||||
/* Add billing id information */
|
||||
if ((ast_aoc_set_billing_id(decoded, AST_AOC_BILLING_NORMAL) ||
|
||||
(ast_aoc_get_billing_id(decoded) != AST_AOC_BILLING_NORMAL))) {
|
||||
|
||||
ast_test_status_update(test, "TEST 1, could not set billing id correctly\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
|
||||
}
|
||||
|
||||
/* Set currency information, verify results*/
|
||||
if ((ast_aoc_set_currency_info(decoded, 100, AST_AOC_MULT_ONE, "usd")) ||
|
||||
(ast_aoc_set_total_type(decoded, AST_AOC_SUBTOTAL)) ||
|
||||
(ast_aoc_get_total_type(decoded) != AST_AOC_SUBTOTAL) ||
|
||||
(ast_aoc_get_currency_amount(decoded) != 100) ||
|
||||
(ast_aoc_get_currency_multiplier(decoded) != AST_AOC_MULT_ONE) ||
|
||||
(strcmp(ast_aoc_get_currency_name(decoded), "usd"))) {
|
||||
|
||||
ast_test_status_update(test, "Test 1: failed to set currency info\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
|
||||
/* Set a currency name larger than 10 characters which is the the maximum
|
||||
* length allowed by the ETSI aoc standard. The name is expected to truncate
|
||||
* to 10 characters. */
|
||||
if ((ast_aoc_set_currency_info(decoded, 100, AST_AOC_MULT_ONE, "12345678901234567890")) ||
|
||||
(ast_aoc_get_currency_amount(decoded) != 100) ||
|
||||
(ast_aoc_get_currency_multiplier(decoded) != AST_AOC_MULT_ONE) ||
|
||||
(strcmp(ast_aoc_get_currency_name(decoded), "1234567890"))) {
|
||||
|
||||
ast_test_status_update(test, "Test 1: failed to set currency info currency name exceeding limit\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
|
||||
/* Encode the message */
|
||||
if (ast_aoc_test_encode_decode_match(decoded)) {
|
||||
ast_test_status_update(test, "Test1: encode decode routine did not match expected results \n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
/* cleanup decoded msg */
|
||||
decoded = ast_aoc_destroy_decoded(decoded);
|
||||
|
||||
/* ---- Test 2 ---- create AOC-E message with charge type == unit */
|
||||
/* create AOC-E message */
|
||||
if (!(decoded = ast_aoc_create(AST_AOC_E, AST_AOC_CHARGE_UNIT, 0)) ||
|
||||
(ast_aoc_get_msg_type(decoded) != AST_AOC_E) ||
|
||||
(ast_aoc_get_charge_type(decoded) != AST_AOC_CHARGE_UNIT)) {
|
||||
|
||||
ast_test_status_update(test, "Test 2: failed to create AOC-E message\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
|
||||
/* Set unit information, verify results*/
|
||||
if ((ast_aoc_add_unit_entry(decoded, 1, 1, 1, 2)) ||
|
||||
(!ast_aoc_add_unit_entry(decoded, 0, 123, 0, 123)) || /* this entry should fail since either number nor type are present */
|
||||
(ast_aoc_add_unit_entry(decoded, 0, 2, 1, 3)) ||
|
||||
(ast_aoc_add_unit_entry(decoded, 1, 3, 0, 4))) {
|
||||
|
||||
ast_test_status_update(test, "Test 2: failed to set unit info\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
|
||||
/* verify unit list is correct */
|
||||
if (ast_aoc_get_unit_count(decoded) == 3) {
|
||||
int i;
|
||||
const struct ast_aoc_unit_entry *unit;
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (!(unit = ast_aoc_get_unit_info(decoded, i)) ||
|
||||
((unit->valid_amount) && (unit->amount != (i+1))) ||
|
||||
((unit->valid_type) && (unit->type != (i+2)))) {
|
||||
ast_test_status_update(test, "TEST 2, invalid unit entry result, got %d,%d, expected %d,%d\n",
|
||||
unit->amount,
|
||||
unit->type,
|
||||
i+1,
|
||||
i+2);
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ast_test_status_update(test, "TEST 2, invalid unit list entry count \n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
|
||||
|
||||
/* Test charging association information */
|
||||
{
|
||||
const struct ast_aoc_charging_association *ca;
|
||||
if ((ast_aoc_set_association_id(decoded, 1234)) ||
|
||||
(!(ca = ast_aoc_get_association_info(decoded)))) {
|
||||
ast_test_status_update(test, "TEST 2, could not set charging association id info correctly\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
|
||||
if ((ca->charging_type != AST_AOC_CHARGING_ASSOCIATION_ID) || (ca->charge.id != 1234)) {
|
||||
ast_test_status_update(test, "TEST 2, could not get charging association id info correctly, 2\n");
|
||||
}
|
||||
|
||||
if ((ast_aoc_set_association_number(decoded, "1234", 16)) ||
|
||||
(!(ca = ast_aoc_get_association_info(decoded)))) {
|
||||
ast_test_status_update(test, "TEST 2, could not set charging association number info correctly, 3\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
|
||||
if ((ca->charging_type != AST_AOC_CHARGING_ASSOCIATION_NUMBER) ||
|
||||
(ca->charge.number.plan != 16) ||
|
||||
(strcmp(ca->charge.number.number, "1234"))) {
|
||||
ast_test_status_update(test, "TEST 2, could not get charging association number info correctly\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Test every billing id possiblity */
|
||||
{
|
||||
int billid[9] = {
|
||||
AST_AOC_BILLING_NA,
|
||||
AST_AOC_BILLING_NORMAL,
|
||||
AST_AOC_BILLING_REVERSE_CHARGE,
|
||||
AST_AOC_BILLING_CREDIT_CARD,
|
||||
AST_AOC_BILLING_CALL_FWD_UNCONDITIONAL,
|
||||
AST_AOC_BILLING_CALL_FWD_BUSY,
|
||||
AST_AOC_BILLING_CALL_FWD_NO_REPLY,
|
||||
AST_AOC_BILLING_CALL_DEFLECTION,
|
||||
AST_AOC_BILLING_CALL_TRANSFER,
|
||||
};
|
||||
int i;
|
||||
|
||||
/* these should fail */
|
||||
if (!(ast_aoc_set_billing_id(decoded, (AST_AOC_BILLING_NA - 1))) ||
|
||||
!(ast_aoc_set_billing_id(decoded, (AST_AOC_BILLING_CALL_TRANSFER + 1)))) {
|
||||
|
||||
ast_test_status_update(test, "TEST 2, setting invalid billing id should fail\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_LEN(billid); i++) {
|
||||
if ((ast_aoc_set_billing_id(decoded, billid[i]) ||
|
||||
(ast_aoc_get_billing_id(decoded) != billid[i]))) {
|
||||
|
||||
ast_test_status_update(test, "TEST 2, could not set billing id correctly, iteration #%d\n", i);
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Encode the message */
|
||||
if (ast_aoc_test_encode_decode_match(decoded)) {
|
||||
ast_test_status_update(test, "Test2: encode decode routine did not match expected results \n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
/* cleanup decoded msg */
|
||||
decoded = ast_aoc_destroy_decoded(decoded);
|
||||
|
||||
/* ---- Test 3 ---- create AOC-Request. test all possible combinations */
|
||||
{
|
||||
int request[7] = { /* all possible request combinations */
|
||||
AST_AOC_REQUEST_S,
|
||||
AST_AOC_REQUEST_D,
|
||||
AST_AOC_REQUEST_E,
|
||||
(AST_AOC_REQUEST_S | AST_AOC_REQUEST_D),
|
||||
(AST_AOC_REQUEST_S | AST_AOC_REQUEST_E),
|
||||
(AST_AOC_REQUEST_D | AST_AOC_REQUEST_E),
|
||||
(AST_AOC_REQUEST_D | AST_AOC_REQUEST_E | AST_AOC_REQUEST_S)
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_LEN(request); i++) {
|
||||
if (!(decoded = ast_aoc_create(AST_AOC_REQUEST, 0, request[i])) ||
|
||||
(ast_aoc_get_msg_type(decoded) != AST_AOC_REQUEST) ||
|
||||
(ast_aoc_get_termination_request(decoded)) ||
|
||||
(ast_aoc_get_request(decoded) != request[i])) {
|
||||
|
||||
ast_test_status_update(test, "Test 3: failed to create AOC-Request message, iteration #%d\n", i);
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
|
||||
/* Encode the message */
|
||||
if (ast_aoc_test_encode_decode_match(decoded)) {
|
||||
ast_test_status_update(test, "Test3: encode decode routine did not match expected results, iteration #%d\n", i);
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
/* cleanup decoded msg */
|
||||
decoded = ast_aoc_destroy_decoded(decoded);
|
||||
}
|
||||
|
||||
|
||||
/* Test termination Request Type */
|
||||
if (!(decoded = ast_aoc_create(AST_AOC_REQUEST, 0, AST_AOC_REQUEST_E)) ||
|
||||
(ast_aoc_set_termination_request(decoded)) ||
|
||||
(!ast_aoc_get_termination_request(decoded)) ||
|
||||
(ast_aoc_get_msg_type(decoded) != AST_AOC_REQUEST) ||
|
||||
(ast_aoc_get_request(decoded) != AST_AOC_REQUEST_E)) {
|
||||
|
||||
ast_test_status_update(test, "Test 3: failed to create AOC-Request message with Termination Request set\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
|
||||
/* Encode the message */
|
||||
if (ast_aoc_test_encode_decode_match(decoded)) {
|
||||
ast_test_status_update(test, "Test3: encode decode routine did not match expected results with termination request set\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
/* cleanup decoded msg */
|
||||
decoded = ast_aoc_destroy_decoded(decoded);
|
||||
}
|
||||
|
||||
/* ---- Test 4 ---- Make stuff blow up */
|
||||
if ((decoded = ast_aoc_create(AST_AOC_D, 1234567, 0))) {
|
||||
|
||||
ast_test_status_update(test, "Test 4: aoc-d creation with no valid charge type should fail\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
if ((decoded = ast_aoc_create(AST_AOC_REQUEST, 0, 0))) {
|
||||
|
||||
ast_test_status_update(test, "Test 4: aoc request creation with no data should have failed\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
if ((decoded = ast_aoc_create(AST_AOC_REQUEST, -12345678, -23456789))) {
|
||||
|
||||
ast_test_status_update(test, "Test 4: aoc request creation with random data should have failed\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
|
||||
/* ---- Test 5 ---- create AOC-E message with charge type == FREE and charge type == NA */
|
||||
/* create AOC-E message */
|
||||
if (!(decoded = ast_aoc_create(AST_AOC_E, AST_AOC_CHARGE_FREE, 0)) ||
|
||||
(ast_aoc_get_msg_type(decoded) != AST_AOC_E) ||
|
||||
(ast_aoc_get_charge_type(decoded) != AST_AOC_CHARGE_FREE)) {
|
||||
|
||||
ast_test_status_update(test, "Test 5: failed to create AOC-E message, charge type Free\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
if (ast_aoc_test_encode_decode_match(decoded)) {
|
||||
ast_test_status_update(test, "Test5: encode decode routine did not match expected results, charge type Free\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
/* cleanup decoded msg */
|
||||
decoded = ast_aoc_destroy_decoded(decoded);
|
||||
|
||||
/* create AOC-E message */
|
||||
if (!(decoded = ast_aoc_create(AST_AOC_E, AST_AOC_CHARGE_NA, 0)) ||
|
||||
(ast_aoc_get_msg_type(decoded) != AST_AOC_E) ||
|
||||
(ast_aoc_get_charge_type(decoded) != AST_AOC_CHARGE_NA)) {
|
||||
|
||||
ast_test_status_update(test, "Test 5: failed to create AOC-E message, charge type NA\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
if (ast_aoc_test_encode_decode_match(decoded)) {
|
||||
ast_test_status_update(test, "Test5: encode decode routine did not match expected results, charge type NA.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
/* cleanup decoded msg */
|
||||
decoded = ast_aoc_destroy_decoded(decoded);
|
||||
|
||||
|
||||
/* ---- TEST 6, AOC-S encode decode */
|
||||
if (!(decoded = ast_aoc_create(AST_AOC_S, 0, 0))) {
|
||||
ast_test_status_update(test, "failed to create AOC-S message for encode decode testing.\n");
|
||||
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
|
||||
ast_aoc_s_add_rate_duration(decoded,
|
||||
AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE,
|
||||
937,
|
||||
AST_AOC_MULT_THOUSAND,
|
||||
"jkasdf",
|
||||
235328,
|
||||
AST_AOC_TIME_SCALE_SECOND,
|
||||
905423,
|
||||
AST_AOC_TIME_SCALE_DAY,
|
||||
1);
|
||||
|
||||
ast_aoc_s_add_rate_flat(decoded,
|
||||
AST_AOC_CHARGED_ITEM_CALL_SETUP,
|
||||
1337,
|
||||
AST_AOC_MULT_ONEHUNDREDTH,
|
||||
"MONEYS");
|
||||
|
||||
ast_aoc_s_add_rate_volume(decoded,
|
||||
AST_AOC_CHARGED_ITEM_CALL_ATTEMPT,
|
||||
AST_AOC_VOLUME_UNIT_SEGMENT,
|
||||
5555,
|
||||
AST_AOC_MULT_ONEHUNDREDTH,
|
||||
"pounds");
|
||||
|
||||
ast_aoc_s_add_rate_duration(decoded,
|
||||
AST_AOC_CHARGED_ITEM_CALL_ATTEMPT,
|
||||
78923,
|
||||
AST_AOC_MULT_ONETHOUSANDTH,
|
||||
"SNAP",
|
||||
9354,
|
||||
AST_AOC_TIME_SCALE_HUNDREDTH_SECOND,
|
||||
234933,
|
||||
AST_AOC_TIME_SCALE_SECOND,
|
||||
0);
|
||||
|
||||
ast_aoc_s_add_rate_free(decoded, AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT, 1);
|
||||
ast_aoc_s_add_rate_free(decoded, AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT, 0);
|
||||
ast_aoc_s_add_rate_na(decoded, AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT);
|
||||
|
||||
if (ast_aoc_test_encode_decode_match(decoded)) {
|
||||
ast_test_status_update(test, "Test6: encode decode routine for AOC-S did not match expected results\n");
|
||||
res = AST_TEST_FAIL;
|
||||
goto cleanup_aoc_test;
|
||||
}
|
||||
/* cleanup decoded msg */
|
||||
decoded = ast_aoc_destroy_decoded(decoded);
|
||||
|
||||
|
||||
|
||||
cleanup_aoc_test:
|
||||
|
||||
decoded = ast_aoc_destroy_decoded(decoded);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
AST_TEST_UNREGISTER(aoc_encode_decode_test);
|
||||
AST_TEST_UNREGISTER(aoc_event_generation_test);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
AST_TEST_REGISTER(aoc_encode_decode_test);
|
||||
AST_TEST_REGISTER(aoc_event_generation_test);
|
||||
return AST_MODULE_LOAD_SUCCESS;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "AOC unit tests");
|
Loading…
Reference in new issue