[svn-commits] dvossel: branch group/v6-new r267443 - in /team/group/v6-new: doc/ include/as...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Jun 3 09:43:32 CDT 2010


Author: dvossel
Date: Thu Jun  3 09:43:28 2010
New Revision: 267443

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=267443
Log:
addition of missing aoc files

Added:
    team/group/v6-new/doc/advice_of_charge.txt   (with props)
    team/group/v6-new/include/asterisk/aoc.h   (with props)
    team/group/v6-new/main/aoc.c   (with props)
    team/group/v6-new/tests/test_aoc.c   (with props)

Added: team/group/v6-new/doc/advice_of_charge.txt
URL: http://svnview.digium.com/svn/asterisk/team/group/v6-new/doc/advice_of_charge.txt?view=auto&rev=267443
==============================================================================
--- team/group/v6-new/doc/advice_of_charge.txt (added)
+++ team/group/v6-new/doc/advice_of_charge.txt Thu Jun  3 09:43:28 2010
@@ -1,0 +1,189 @@
+================
+Advice of Charge
+================
+
+Written by: David Vossel
+Initial version: 04-19-2010
+Email: dvossel at digium.com
+
+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.
+
+--------------------------------------
+|          READ THIS FIRST           |
+--------------------------------------
+PLEASE REPORT ANY ISSUES ENCOUNTERED WHILE USING AOC.  This feature
+has had very little community feedback so far.  If you are using this
+feature please share with us any problems you are having and any
+improvements that could make this feature more useful.  Thank you!
+
+--------------------------------------
+|           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

Propchange: team/group/v6-new/doc/advice_of_charge.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/group/v6-new/doc/advice_of_charge.txt
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/group/v6-new/doc/advice_of_charge.txt
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/group/v6-new/include/asterisk/aoc.h
URL: http://svnview.digium.com/svn/asterisk/team/group/v6-new/include/asterisk/aoc.h?view=auto&rev=267443
==============================================================================
--- team/group/v6-new/include/asterisk/aoc.h (added)
+++ team/group/v6-new/include/asterisk/aoc.h Thu Jun  3 09:43:28 2010
@@ -1,0 +1,584 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * David Vossel <dvossel at 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 at 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_ */

Propchange: team/group/v6-new/include/asterisk/aoc.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/group/v6-new/include/asterisk/aoc.h
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/group/v6-new/include/asterisk/aoc.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/group/v6-new/main/aoc.c
URL: http://svnview.digium.com/svn/asterisk/team/group/v6-new/main/aoc.c?view=auto&rev=267443
==============================================================================
--- team/group/v6-new/main/aoc.c (added)
+++ team/group/v6-new/main/aoc.c Thu Jun  3 09:43:28 2010
@@ -1,0 +1,1607 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * David Vossel <dvossel at 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 payload generation encoding and decoding
+ *
+ * \author David Vossel <dvossel at digium.com>
+ */
+
+#include "asterisk.h"
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
+
+#include "asterisk/aoc.h"
+#include "asterisk/utils.h"
+#include "asterisk/strings.h"
+#include "asterisk/_private.h"
+#include "asterisk/cli.h"
+#include "asterisk/manager.h"
+
+/* Encoded Payload Flags */
+#define AST_AOC_ENCODED_TYPE_REQUEST    (0 << 0)
+#define AST_AOC_ENCODED_TYPE_D          (1 << 0)
+#define AST_AOC_ENCODED_TYPE_E          (2 << 0)
+#define AST_AOC_ENCODED_TYPE_S          (3 << 0)
+
+#define AST_AOC_ENCODED_REQUEST_S       (1 << 2)
+#define AST_AOC_ENCODED_REQUEST_D       (1 << 3)
+#define AST_AOC_ENCODED_REQUEST_E       (1 << 4)
+
+#define AST_AOC_ENCODED_CHARGE_NA       (0 << 5)
+#define AST_AOC_ENCODED_CHARGE_FREE     (1 << 5)
+#define AST_AOC_ENCODED_CHARGE_CURRENCY (2 << 5)
+#define AST_AOC_ENCODED_CHARGE_UNIT     (3 << 5)
+
+#define AST_AOC_ENCODED_CHARGE_SUBTOTAL (1 << 7)
+#define AST_AOC_ENCODED_CHARGE_TOTAL    (0 << 7)
+
+#define AST_AOC_ENCODE_VERSION 1
+
+
+static char aoc_debug_enabled = 0;
+static void aoc_display_decoded_debug(const struct ast_aoc_decoded *decoded, int decoding, struct ast_channel *chan);
+static int aoc_s_add_entry(struct ast_aoc_decoded *decoded, struct ast_aoc_s_entry *entry);
+
+/* AOC Payload Header. Holds all the encoded AOC data to pass on the wire */
+struct ast_aoc_encoded {
+	uint8_t  version;
+	uint8_t  flags;
+	uint16_t datalen;
+	unsigned char data[0];
+};
+
+/* Decoded AOC data */
+struct ast_aoc_decoded {
+	enum ast_aoc_type msg_type;
+	enum ast_aoc_charge_type charge_type;
+	enum ast_aoc_request request_flag;
+	enum ast_aoc_total_type total_type;
+
+	/* currency information */
+	enum ast_aoc_currency_multiplier multiplier;
+	unsigned int currency_amount;
+	char currency_name[AOC_CURRENCY_NAME_SIZE];
+
+	/* unit information */
+	int unit_count;
+	struct ast_aoc_unit_entry unit_list[32];
+
+	/* Billing Id */
+	enum ast_aoc_billing_id billing_id;
+
+	/* Charging Association information */
+	struct ast_aoc_charging_association charging_association;
+
+	/* AOC-S charge information */
+	int aoc_s_count;
+	struct ast_aoc_s_entry aoc_s_entries[10];
+
+	/* Is this an AOC Termination Request */
+	char termination_request;
+};
+
+/*! \brief AOC Payload Information Elements */
+enum AOC_IE {
+	AOC_IE_CURRENCY = 1,
+	AOC_IE_UNIT = 2,
+	AOC_IE_BILLING = 3,
+	AOC_IE_CHARGING_ASSOCIATION = 4,
+	AOC_IE_RATE = 5,
+	AOC_IE_TERMINATION_REQUEST = 6,
+};
+
+/*! \brief AOC IE payload header */
+struct aoc_pl_ie_hdr {
+	uint8_t ie_id;
+	uint8_t datalen;
+	char data[0];
+} __attribute__((packed));
+
+struct aoc_ie_currency {
+	uint32_t amount;
+	uint8_t  multiplier;
+	char name[AOC_CURRENCY_NAME_SIZE];
+} __attribute__((packed));
+
+struct aoc_ie_unit {
+	uint32_t amount;
+	uint8_t valid_type;
+	uint8_t valid_amount;
+	uint8_t type;
+} __attribute__((packed));
+
+struct aoc_ie_billing {
+	uint8_t id;
+} __attribute__((packed));
+
+struct aoc_ie_charging_association {
+	struct ast_aoc_charging_association ca;
+} __attribute__((packed));
+
+struct aoc_ie_charging_rate {
+	struct ast_aoc_s_entry entry;
+} __attribute__((packed));
+
+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)
+{
+	struct ast_aoc_decoded *decoded = NULL;
+
+	/* verify input */
+	if (((unsigned int) charge_type > AST_AOC_CHARGE_UNIT) ||
+		((unsigned int) msg_type > AST_AOC_E) ||
+		((msg_type == AST_AOC_REQUEST) && !requests)) {
+
+		ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object, invalid input\n");
+		return NULL;
+	}
+
+	if (!(decoded = ast_calloc(1, sizeof(struct ast_aoc_decoded)))) {
+		ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object \n");
+		return NULL;
+	}
+
+	decoded->msg_type = msg_type;
+
+	if (msg_type == AST_AOC_REQUEST) {
+		decoded->request_flag = requests;
+	} else if ((msg_type == AST_AOC_D) || (msg_type == AST_AOC_E)) {
+		decoded->charge_type = charge_type;
+	}
+
+	return decoded;
+}
+
+void *ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
+{
+	ast_free(decoded);
+	return NULL;
+}
+
+void *ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
+{
+	ast_free(encoded);
+	return NULL;
+}
+
+static void aoc_parse_ie_charging_rate(struct ast_aoc_decoded *decoded, const struct aoc_ie_charging_rate *ie)
+{
+	struct ast_aoc_s_entry entry = { 0, };
+
+	entry.charged_item = ntohs(ie->entry.charged_item);
+	entry.rate_type = ntohs(ie->entry.rate_type);
+
+	switch (entry.rate_type) {
+	case AST_AOC_RATE_TYPE_DURATION:
+		entry.rate.duration.multiplier = ntohs(ie->entry.rate.duration.multiplier);
+		entry.rate.duration.amount = ntohl(ie->entry.rate.duration.amount);
+		entry.rate.duration.time = ntohl(ie->entry.rate.duration.time);
+		entry.rate.duration.time_scale = ntohs(ie->entry.rate.duration.time_scale);
+		entry.rate.duration.granularity_time = ntohl(ie->entry.rate.duration.granularity_time);
+		entry.rate.duration.granularity_time_scale = ntohs(ie->entry.rate.duration.granularity_time_scale);
+		entry.rate.duration.charging_type = ie->entry.rate.duration.charging_type; /* only one byte */
+
+		if (!ast_strlen_zero(ie->entry.rate.duration.currency_name)) {
+			ast_copy_string(entry.rate.duration.currency_name,
+				ie->entry.rate.duration.currency_name,
+				sizeof(entry.rate.duration.currency_name));
+		}
+		break;
+	case AST_AOC_RATE_TYPE_FLAT:
+		entry.rate.flat.multiplier = ntohs(ie->entry.rate.flat.multiplier);
+		entry.rate.flat.amount = ntohl(ie->entry.rate.flat.amount);
+		if (!ast_strlen_zero(ie->entry.rate.flat.currency_name)) {
+			ast_copy_string(entry.rate.flat.currency_name,
+				ie->entry.rate.flat.currency_name,
+				sizeof(entry.rate.flat.currency_name));
+		}
+		break;
+	case AST_AOC_RATE_TYPE_VOLUME:
+		entry.rate.volume.multiplier = ntohs(ie->entry.rate.volume.multiplier);
+		entry.rate.volume.amount = ntohl(ie->entry.rate.volume.amount);
+		entry.rate.volume.volume_unit = ntohs(ie->entry.rate.volume.volume_unit);
+		if (!ast_strlen_zero(ie->entry.rate.volume.currency_name)) {
+			ast_copy_string(entry.rate.volume.currency_name,
+				ie->entry.rate.volume.currency_name,
+				sizeof(entry.rate.volume.currency_name));
+		}
+		break;
+	case AST_AOC_RATE_TYPE_SPECIAL_CODE:
+		entry.rate.special_code = ntohs(ie->entry.rate.special_code);
+		break;
+	}
+
+	aoc_s_add_entry(decoded, &entry);
+}
+
+static int aoc_parse_ie(struct ast_aoc_decoded *decoded, unsigned char *data, unsigned int datalen)
+{
+	enum AOC_IE ie_id;
+	unsigned int len;
+
+	while (datalen >= 2) {
+		ie_id = data[0];
+		len = data[1];
+		if (len > datalen -2) {
+			ast_log(LOG_ERROR, "AOC information element length exceeds the total message size\n");
+			return -1;
+		}
+
+		switch(ie_id) {
+		case AOC_IE_CURRENCY:
+			if (len == sizeof(struct aoc_ie_currency)) {
+				struct aoc_ie_currency ie;
+				memcpy(&ie, data + 2, len);
+				decoded->currency_amount = ntohl(ie.amount);
+				decoded->multiplier = ie.multiplier; /* only one byte */
+				memcpy(decoded->currency_name, ie.name, sizeof(decoded->currency_name));
+			} else {
+				ast_log(LOG_WARNING, "Recieved invalid currency ie\n");
+			}
+			break;
+		case AOC_IE_UNIT:
+			if (len == sizeof(struct aoc_ie_unit)) {
+				struct aoc_ie_unit ie;
+				memcpy(&ie, data + 2, len);
+				ast_aoc_add_unit_entry(decoded, ie.valid_amount, ntohl(ie.amount), ie.valid_type, ie.type);
+			} else {
+				ast_log(LOG_WARNING, "Recieved invalid unit ie\n");
+			}
+			break;
+		case AOC_IE_BILLING:
+			if (len == sizeof(struct aoc_ie_billing)) {
+				struct aoc_ie_billing ie;
+				memcpy(&ie, data + 2, len);
+				decoded->billing_id = ie.id; /* only one byte */
+			} else {
+				ast_log(LOG_WARNING, "Recieved invalid billing ie\n");
+			}
+			break;
+		case AOC_IE_CHARGING_ASSOCIATION:
+			if (len == sizeof(struct aoc_ie_charging_association)) {
+				memcpy(&decoded->charging_association, data + 2, sizeof(decoded->charging_association));
+				/* everything in the charging_association struct is a single byte except for the id */
+				if (decoded->charging_association.charging_type == AST_AOC_CHARGING_ASSOCIATION_ID) {
+					decoded->charging_association.charge.id = ntohl(decoded->charging_association.charge.id);
+				}
+			} else {
+				ast_log(LOG_WARNING, "Recieved invalid charging association ie\n");
+			}
+			break;
+		case AOC_IE_RATE:
+			if (len == sizeof(struct aoc_ie_charging_rate)) {
+				struct aoc_ie_charging_rate ie;
+				memcpy(&ie, data + 2, len);
+				aoc_parse_ie_charging_rate(decoded, &ie);
+			} else {
+				ast_log(LOG_WARNING, "Recieved invalid charging rate ie\n");
+			}
+			break;
+		case AOC_IE_TERMINATION_REQUEST:
+			if (len == 0) {
+				decoded->termination_request = 1;
+			} else {
+				ast_log(LOG_WARNING, "Recieved invalid termination request ie\n");
+			}
+			break;
+		default:
+			ast_log(LOG_WARNING, "Unknown AOC Information Element, ignoring.\n");
+		}
+
+		datalen -= (len + 2);
+		data += (len + 2);
+	}
+	return 0;
+}
+
+struct ast_aoc_decoded *ast_aoc_decode(struct ast_aoc_encoded *encoded, size_t size, struct ast_channel *chan)
+{
+	struct ast_aoc_decoded *decoded;
+
+	/* verify our encoded payload is actually large enough to hold all the ies */
+	if ((size - (sizeof(struct ast_aoc_encoded)) != ntohs(encoded->datalen))) {
+		ast_log(LOG_WARNING, "Corrupted aoc encoded object, can not decode\n");
+		return NULL;
+	}
+
+	if (!(decoded = ast_calloc(1, sizeof(struct ast_aoc_decoded)))) {
+		ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object \n");
+		return NULL;
+	}
+
+	/* decode flags */
+
+	if ((encoded->flags & AST_AOC_ENCODED_TYPE_S) == AST_AOC_ENCODED_TYPE_S) {
+		decoded->msg_type = AST_AOC_S;
+	} else if (encoded->flags & AST_AOC_ENCODED_TYPE_E) {
+		decoded->msg_type = AST_AOC_E;
+	} else if (encoded->flags & AST_AOC_ENCODED_TYPE_D) {
+		decoded->msg_type = AST_AOC_D;
+	} else {
+		decoded->msg_type = AST_AOC_REQUEST;
+	}
+
+	if (decoded->msg_type == AST_AOC_REQUEST) {

[... 1988 lines stripped ...]



More information about the svn-commits mailing list