Merge Call completion support into trunk.

From Reviewboard:
CCSS stands for Call Completion Supplementary Services. An admittedly out-of-date
overview of the architecture can be found in the file doc/CCSS_architecture.pdf
in the CCSS branch. Off the top of my head, the big differences between what is
implemented and what is in the document are as follows:

1. We did not end up modifying the Hangup application at all.
2. The document states that a single call completion monitor may be used across
   multiple calls to the same device. This proved to not be such a good idea
   when implementing protocol-specific monitors, and so we ended up using one
   monitor per-device per-call.
3. There are some configuration options which were conceived after the document
   was written. These are documented in the ccss.conf.sample that is on this
   review request.
		      
For some basic understanding of terminology used throughout this code, see the
ccss.tex document that is on this review.

This implements CCBS and CCNR in several flavors.

First up is a "generic" implementation, which can work over any channel technology
provided that the channel technology can accurately report device state. Call
completion is requested using the dialplan application CallCompletionRequest and can
be canceled using CallCompletionCancel. Device state subscriptions are used in order
to monitor the state of called parties.

Next, there is a SIP-specific implementation of call completion. This method uses the
methods outlined in draft-ietf-bliss-call-completion-06 to implement call completion
using SIP signaling. There are a few things to note here:

* The agent/monitor terminology used throughout Asterisk sometimes is the reverse of
  what is defined in the referenced draft.

* Implementation of the draft required support for SIP PUBLISH. I attempted to write
  this in a generic-enough fashion such that if someone were to want to write PUBLISH
  support for other event packages, such as dialog-state or presence, most of the effort
  would be in writing callbacks specific to the event package.

* A subportion of supporting PUBLISH reception was that we had to implement a PIDF
  parser. The PIDF support added is a bit minimal. I first wrote a validation
  routine to ensure that the PIDF document is formatted properly. The rest of the
  PIDF reading is done in-line in the call-completion-specific PUBLISH-handling
  code. In other words, while there is PIDF support here, it is not in any state
  where it could easily be applied to other event packages as is.

Finally, there are a variety of ISDN-related call completion protocols supported. These
were written by Richard Mudgett, and as such I can't really say much about their
implementation. There are notes in the CHANGES file that indicate the ISDN protocols
over which call completion is supported.

Review: https://reviewboard.asterisk.org/r/523


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@256528 65c4cc65-6c06-0410-ace0-fbb531ad65f3
certified/1.8.6
Mark Michelson 15 years ago
parent 6cad0f1602
commit e24661fd18

@ -387,6 +387,13 @@ Calendaring for Asterisk
iCalendar, CalDAV, and Exchange Server calendars are supported (Exchange support
only tested on Exchange Server 2003 with no support for forms-based authentication).
Call Completion Supplementary Services for Asterisk
---------------------------------------------------
* Call completion support has been added for SIP, DAHDI/ISDN, and DAHDI/analog.
DAHDI/ISDN supports call completion for the following switch types:
EuroIsdn(ETSI) for PTP and PTMP modes, and Qsig.
See doc/CCSS_architecture.pdf and doc/tex/ccss.tex(asterisk.pdf) for details.
Multicast RTP Support
---------------------
* A new RTP engine and channel driver have been added which supports Multicast RTP.

@ -62,6 +62,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/global_datastores.h"
#include "asterisk/dsp.h"
#include "asterisk/cel.h"
#include "asterisk/ccss.h"
#include "asterisk/indications.h"
/*** DOCUMENTATION
@ -810,6 +811,12 @@ static void do_forward(struct chanlist *o,
ast_channel_make_compatible(o->chan, in);
ast_channel_inherit_variables(in, o->chan);
ast_channel_datastore_inherit(in, o->chan);
/* When a call is forwarded, we don't want to track new interfaces
* dialed for CC purposes. Setting the done flag will ensure that
* any Dial operations that happen later won't record CC interfaces.
*/
ast_ignore_cc(o->chan);
ast_log(LOG_NOTICE, "Not accepting call completion offers from call-forward recipient %s\n", o->chan->name);
} else
ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
}
@ -904,7 +911,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
struct chanlist *outgoing, int *to, struct ast_flags64 *peerflags,
char *opt_args[],
struct privacy_args *pa,
const struct cause_args *num_in, int *result, char *dtmf_progress)
const struct cause_args *num_in, int *result, char *dtmf_progress,
const int ignore_cc)
{
struct cause_args num = *num_in;
int prestart = num.busy + num.congestion + num.nochan;
@ -917,6 +925,10 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
#endif
struct ast_party_connected_line connected_caller;
struct ast_str *featurecode = ast_str_alloca(FEATURE_MAX_LEN + 1);
int cc_recall_core_id;
int is_cc_recall;
int cc_frame_received = 0;
int num_ringing = 0;
ast_party_connected_line_init(&connected_caller);
if (single) {
@ -938,6 +950,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
}
}
is_cc_recall = ast_cc_is_recall(in, &cc_recall_core_id, NULL);
#ifdef HAVE_EPOLL
for (epollo = outgoing; epollo; epollo = epollo->next)
ast_poll_channel_add(in, epollo->chan);
@ -970,6 +984,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
ast_verb(3, "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan);
}
*to = 0;
if (is_cc_recall) {
ast_cc_failed(cc_recall_core_id, "Everyone is busy/congested for the recall. How sad");
}
return NULL;
}
winner = ast_waitfor_n(watchers, pos, to);
@ -1014,6 +1031,15 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
/* here, o->chan == c == winner */
if (!ast_strlen_zero(c->call_forward)) {
pa->sentringing = 0;
if (!ignore_cc && (f = ast_read(c))) {
if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_CC) {
/* This channel is forwarding the call, and is capable of CC, so
* be sure to add the new device interface to the list
*/
ast_handle_cc_control_frame(in, c, f->data.ptr);
}
ast_frfree(f);
}
do_forward(o, &num, peerflags, single, to);
continue;
}
@ -1088,13 +1114,41 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
handle_cause(AST_CAUSE_CONGESTION, &num);
break;
case AST_CONTROL_RINGING:
ast_verb(3, "%s is ringing\n", c->name);
/* Setup early media if appropriate */
if (single && CAN_EARLY_BRIDGE(peerflags, in, c))
ast_channel_early_bridge(in, c);
if (!(pa->sentringing) && !ast_test_flag64(outgoing, OPT_MUSICBACK) && ast_strlen_zero(opt_args[OPT_ARG_RINGBACK])) {
ast_indicate(in, AST_CONTROL_RINGING);
pa->sentringing++;
/* This is a tricky area to get right when using a native
* CC agent. The reason is that we do the best we can to send only a
* single ringing notification to the caller.
*
* Call completion complicates the logic used here. CCNR is typically
* offered during a ringing message. Let's say that party A calls
* parties B, C, and D. B and C do not support CC requests, but D
* does. If we were to receive a ringing notification from B before
* the others, then we would end up sending a ringing message to
* A with no CCNR offer present.
*
* The approach that we have taken is that if we receive a ringing
* response from a party and no CCNR offer is present, we need to
* wait. Specifically, we need to wait until either a) a called party
* offers CCNR in its ringing response or b) all called parties have
* responded in some way to our call and none offers CCNR.
*
* The drawback to this is that if one of the parties has a delayed
* response or, god forbid, one just plain doesn't respond to our
* outgoing call, then this will result in a significant delay between
* when the caller places the call and hears ringback.
*
* Note also that if CC is disabled for this call, then it is perfectly
* fine for ringing frames to get sent through.
*/
++num_ringing;
if (ignore_cc || cc_frame_received || num_ringing == numlines) {
ast_verb(3, "%s is ringing\n", c->name);
/* Setup early media if appropriate */
if (single && CAN_EARLY_BRIDGE(peerflags, in, c))
ast_channel_early_bridge(in, c);
if (!(pa->sentringing) && !ast_test_flag64(outgoing, OPT_MUSICBACK) && ast_strlen_zero(opt_args[OPT_ARG_RINGBACK])) {
ast_indicate(in, AST_CONTROL_RINGING);
pa->sentringing++;
}
}
break;
case AST_CONTROL_PROGRESS:
@ -1163,6 +1217,12 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
case AST_CONTROL_FLASH:
/* Ignore going off hook and flash */
break;
case AST_CONTROL_CC:
if (!ignore_cc) {
ast_handle_cc_control_frame(in, c, f->data.ptr);
cc_frame_received = 1;
}
break;
case -1:
if (!ast_test_flag64(outgoing, OPT_RINGBACK | OPT_MUSICBACK)) {
ast_verb(3, "%s stopped sounds\n", c->name);
@ -1212,6 +1272,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
}
ast_frfree(f);
}
if (is_cc_recall) {
ast_cc_completed(in, "CC completed, although the caller hung up (cancelled)");
}
return NULL;
}
@ -1229,6 +1292,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
strcpy(pa->status, "CANCEL");
ast_frfree(f);
ast_channel_unlock(in);
if (is_cc_recall) {
ast_cc_completed(in, "CC completed, but the caller used DTMF to exit");
}
return NULL;
}
ast_channel_unlock(in);
@ -1241,6 +1307,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
strcpy(pa->status, "CANCEL");
ast_cdr_noanswer(in->cdr);
ast_frfree(f);
if (is_cc_recall) {
ast_cc_completed(in, "CC completed, but the caller hung up with DTMF");
}
return NULL;
}
}
@ -1283,6 +1352,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
}
#endif
if (is_cc_recall) {
ast_cc_completed(in, "Recall completed!");
}
return peer;
}
@ -1656,6 +1728,8 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
char *opt_args[OPT_ARG_ARRAY_SIZE];
struct ast_datastore *datastore = NULL;
int fulldial = 0, num_dialed = 0;
int ignore_cc = 0;
char device_name[AST_CHANNEL_NAME];
/* Reset all DIAL variables back to blank, to prevent confusion (in case we don't reset all of them). */
pbx_builtin_setvar_helper(chan, "DIALSTATUS", "");
@ -1686,6 +1760,10 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
goto done;
}
if (ast_cc_call_init(chan, &ignore_cc)) {
goto done;
}
if (ast_test_flag64(&opts, OPT_SCREEN_NOINTRO) && !ast_strlen_zero(opt_args[OPT_ARG_SCREEN_NOINTRO])) {
delprivintro = atoi(opt_args[OPT_ARG_SCREEN_NOINTRO]);
@ -1871,8 +1949,17 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
if (!rest) /* we are on the last destination */
chan->hangupcause = cause;
chanlist_free(tmp);
if (!ignore_cc && (cause == AST_CAUSE_BUSY || cause == AST_CAUSE_CONGESTION)) {
if (!ast_cc_callback(chan, tech, numsubst, ast_cc_busy_interface)) {
ast_cc_extension_monitor_add_dialstring(chan, interface, "");
}
}
continue;
}
ast_channel_get_device_name(tc, device_name, sizeof(device_name));
if (!ignore_cc) {
ast_cc_extension_monitor_add_dialstring(chan, interface, device_name);
}
pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", numsubst);
ast_channel_lock(tc);
@ -1965,6 +2052,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
chan->hangupcause = tc->hangupcause;
}
ast_channel_unlock(chan);
ast_cc_call_failed(chan, tc, interface);
ast_hangup(tc);
tc = NULL;
chanlist_free(tmp);
@ -2038,7 +2126,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
}
}
peer = wait_for_answer(chan, outgoing, &to, peerflags, opt_args, &pa, &num, &result, dtmf_progress);
peer = wait_for_answer(chan, outgoing, &to, peerflags, opt_args, &pa, &num, &result, dtmf_progress, ignore_cc);
/* The ast_channel_datastore_remove() function could fail here if the
* datastore was moved to another channel during a masquerade. If this is
@ -2513,6 +2601,7 @@ done:
if (config.start_sound) {
ast_free((char *)config.start_sound);
}
ast_ignore_cc(chan);
return res;
}

File diff suppressed because it is too large Load Diff

@ -545,6 +545,8 @@ static int local_call(struct ast_channel *ast, char *dest, int timeout)
int res;
struct ast_var_t *varptr = NULL, *new;
size_t len, namelen;
char *reduced_dest = ast_strdupa(dest);
char *slash;
if (!p)
return -1;
@ -594,6 +596,8 @@ start_over:
ast_string_field_set(p->chan, musicclass, p->owner->musicclass);
ast_cdr_update(p->chan);
ast_channel_cc_params_init(p->chan, ast_channel_get_cc_config_params(p->owner));
if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) {
ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context);
ast_mutex_unlock(&p->lock);
@ -618,6 +622,14 @@ start_over:
}
}
ast_channel_datastore_inherit(p->owner, p->chan);
/* If the local channel has /n or /b on the end of it,
* we need to lop that off for our argument to setting
* up the CC_INTERFACES variable
*/
if ((slash = strrchr(reduced_dest, '/'))) {
*slash = '\0';
}
ast_set_cc_interfaces_chanvar(p->chan, reduced_dest);
/* Start switch on sub channel */
if (!(res = ast_pbx_start(p->chan)))
@ -857,6 +869,10 @@ static struct ast_channel *local_request(const char *type, format_t format, cons
AST_LIST_UNLOCK(&locals);
p = local_pvt_destroy(p);
}
if (ast_channel_cc_params_init(chan, ast_channel_get_cc_config_params((struct ast_channel *)requestor))) {
chan = ast_channel_release(chan);
p = local_pvt_destroy(p);
}
}
return chan;

File diff suppressed because it is too large Load Diff

@ -169,6 +169,14 @@ static int analog_get_callerid(struct analog_pvt *p, char *name, char *number, e
return -1;
}
static const char *analog_get_orig_dialstring(struct analog_pvt *p)
{
if (p->calls->get_orig_dialstring) {
return p->calls->get_orig_dialstring(p->chan_pvt);
}
return "";
}
static int analog_get_event(struct analog_pvt *p)
{
if (p->calls->get_event) {
@ -934,6 +942,24 @@ int analog_call(struct analog_pvt *p, struct ast_channel *ast, char *rdest, int
ast_setstate(ast, AST_STATE_RINGING);
index = analog_get_index(ast, p, 0);
if (index > -1) {
struct ast_cc_config_params *cc_params;
/* This is where the initial ringing frame is queued for an analog call.
* As such, this is a great time to offer CCNR to the caller if it's available.
*/
cc_params = ast_channel_get_cc_config_params(p->subs[index].owner);
if (cc_params) {
switch (ast_get_cc_monitor_policy(cc_params)) {
case AST_CC_MONITOR_NEVER:
break;
case AST_CC_MONITOR_NATIVE:
case AST_CC_MONITOR_ALWAYS:
case AST_CC_MONITOR_GENERIC:
ast_queue_cc_frame(p->subs[index].owner, AST_CC_GENERIC_MONITOR_TYPE,
analog_get_orig_dialstring(p), AST_CC_CCNR, NULL);
break;
}
}
ast_queue_control(p->subs[index].owner, AST_CONTROL_RINGING);
}
break;

@ -213,6 +213,8 @@ struct analog_callback {
void (* const cancel_cidspill)(void *pvt);
int (* const confmute)(void *pvt, int mute);
void (* const set_pulsedial)(void *pvt, int flag);
const char *(* const get_orig_dialstring)(void *pvt);
};

File diff suppressed because it is too large Load Diff

@ -27,8 +27,44 @@
#include "asterisk/channel.h"
#include "asterisk/frame.h"
#include "asterisk/ccss.h"
#include <libpri.h>
#include <dahdi/user.h>
#if defined(PRI_SUBCMD_CC_AVAILABLE)
/* BUGBUG the HAVE_PRI_CCSS line is to be removed when the CCSS branch is merged to trunk and the configure script is updated. */
#define HAVE_PRI_CCSS 1
#endif /* defined(PRI_SUBCMD_CC_AVAILABLE) */
#if defined(HAVE_PRI_CCSS)
/*! PRI debug message flags when normal PRI debugging is turned on at the command line. */
#define SIG_PRI_DEBUG_NORMAL \
(PRI_DEBUG_APDU | PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE | PRI_DEBUG_Q921_STATE \
| PRI_DEBUG_CC)
/*! PRI debug message flags when intense PRI debugging is turned on at the command line. */
#define SIG_PRI_DEBUG_INTENSE \
(PRI_DEBUG_APDU | PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE | PRI_DEBUG_Q921_STATE \
| PRI_DEBUG_CC | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_DUMP)
#else
/*! PRI debug message flags when normal PRI debugging is turned on at the command line. */
#define SIG_PRI_DEBUG_NORMAL \
(PRI_DEBUG_APDU | PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE | PRI_DEBUG_Q921_STATE)
/*! PRI debug message flags when intense PRI debugging is turned on at the command line. */
#define SIG_PRI_DEBUG_INTENSE \
(PRI_DEBUG_APDU | PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE | PRI_DEBUG_Q921_STATE \
| PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_DUMP)
#endif /* !defined(HAVE_PRI_CCSS) */
#if 0
/*! PRI debug message flags set on initial startup. */
#define SIG_PRI_DEBUG_DEFAULT SIG_PRI_DEBUG_NORMAL
#else
/*! PRI debug message flags set on initial startup. */
#define SIG_PRI_DEBUG_DEFAULT 0
#endif
enum sig_pri_tone {
SIG_PRI_TONE_RINGTONE = 0,
@ -78,6 +114,14 @@ struct sig_pri_callback {
void (* const set_rdnis)(void *pvt, const char *rdnis);
void (* const queue_control)(void *pvt, int subclass);
int (* const new_nobch_intf)(struct sig_pri_pri *pri);
const char *(* const get_orig_dialstring)(void *pvt);
void (* const make_cc_dialstring)(void *pvt, char *buf, size_t buf_size);
void (* const update_span_devstate)(struct sig_pri_pri *pri);
/*! Reference the parent module. */
void (*module_ref)(void);
/*! Unreference the parent module. */
void (*module_unref)(void);
};
#define NUM_DCHANS 4 /*!< No more than 4 d-channels */
@ -194,6 +238,7 @@ struct sig_pri_chan {
struct sig_pri_pri {
/* Should be set by user */
struct ast_cc_config_params *cc_params; /*!< CC config parameters for each new call. */
int pritimers[PRI_MAX_TIMERS];
int overlapdial; /*!< In overlap dialing mode */
int qsigchannelmapping; /*!< QSIG channel mapping type */
@ -229,6 +274,11 @@ struct sig_pri_pri {
int switchtype; /*!< Type of switch to emulate */
int nsf; /*!< Network-Specific Facilities */
int trunkgroup; /*!< What our trunkgroup is */
#if defined(HAVE_PRI_CCSS)
int cc_ptmp_recall_mode; /*!< CC PTMP recall mode. globalRecall(0), specificRecall(1) */
int cc_qsig_signaling_link_req; /*!< CC Q.SIG signaling link retention (Party A) release(0), retain(1), do-not-care(2) */
int cc_qsig_signaling_link_rsp; /*!< CC Q.SIG signaling link retention (Party B) release(0), retain(1) */
#endif /* defined(HAVE_PRI_CCSS) */
int dchanavail[NUM_DCHANS]; /*!< Whether each channel is available */
int debug; /*!< set to true if to dump PRI event info (tested but never set) */
@ -257,6 +307,37 @@ struct sig_pri_pri {
ast_mutex_t lock; /*!< libpri access Mutex */
time_t lastreset; /*!< time when unused channels were last reset */
struct sig_pri_callback *calls;
/*!
* \brief Congestion device state of the span.
* \details
* AST_DEVICE_NOT_INUSE - Span does not have all B channels in use.
* AST_DEVICE_BUSY - All B channels are in use.
* AST_DEVICE_UNAVAILABLE - Span is in alarm.
* \note
* Device name: DAHDI/I<span>/congestion
*/
int congestion_devstate;
#if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
/*! \todo An ISDN span threshold device state could be useful in determining how often a span utilization goes over a configurable threshold. */
/*!
* \brief User threshold device state of the span.
* \details
* AST_DEVICE_NOT_INUSE - There are no B channels in use.
* AST_DEVICE_INUSE - The number of B channels in use is less than
* the configured threshold but not zero.
* AST_DEVICE_BUSY - The number of B channels in use meets or exceeds
* the configured threshold.
* AST_DEVICE_UNAVAILABLE - Span is in alarm.
* \note
* Device name: DAHDI/I<span>/threshold
*/
int threshold_devstate;
/*!
* \brief Number of B channels in use to consider the span in a busy state.
* \note Setting the threshold to zero is interpreted as all B channels.
*/
int user_busy_threshold;
#endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
};
void sig_pri_extract_called_num_subaddr(struct sig_pri_chan *p, const char *rdest, char *called, size_t called_buff_size);
@ -304,4 +385,25 @@ int pri_maintenance_bservice(struct pri *pri, struct sig_pri_chan *p, int change
void sig_pri_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, struct sig_pri_chan *pchan);
int sig_pri_cc_agent_init(struct ast_cc_agent *agent, struct sig_pri_chan *pvt_chan);
int sig_pri_cc_agent_start_offer_timer(struct ast_cc_agent *agent);
int sig_pri_cc_agent_stop_offer_timer(struct ast_cc_agent *agent);
void sig_pri_cc_agent_req_ack(struct ast_cc_agent *agent);
int sig_pri_cc_agent_status_req(struct ast_cc_agent *agent);
int sig_pri_cc_agent_stop_ringing(struct ast_cc_agent *agent);
int sig_pri_cc_agent_party_b_free(struct ast_cc_agent *agent);
int sig_pri_cc_agent_start_monitoring(struct ast_cc_agent *agent);
int sig_pri_cc_agent_callee_available(struct ast_cc_agent *agent);
void sig_pri_cc_agent_destructor(struct ast_cc_agent *agent);
int sig_pri_cc_monitor_req_cc(struct ast_cc_monitor *monitor, int *available_timer_id);
int sig_pri_cc_monitor_suspend(struct ast_cc_monitor *monitor);
int sig_pri_cc_monitor_unsuspend(struct ast_cc_monitor *monitor);
int sig_pri_cc_monitor_status_rsp(struct ast_cc_monitor *monitor, enum ast_device_state devstate);
int sig_pri_cc_monitor_cancel_available_timer(struct ast_cc_monitor *monitor, int *sched_id);
void sig_pri_cc_monitor_destructor(void *monitor_pvt);
int sig_pri_load(const char *cc_type_name);
void sig_pri_unload(void);
#endif /* _SIG_PRI_H */

@ -153,7 +153,7 @@
* \todo This string should be set dynamically. We only support REFER and SUBSCRIBE if we have
* allowsubscribe and allowrefer on in sip.conf.
*/
#define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO"
#define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH"
/*! \brief SIP Extensions we support
* \note This should be generated based on the previous array
@ -239,6 +239,7 @@
*/
/*@{*/
#define SIP_OUTGOING (1 << 0) /*!< D: Direction of the last transaction in this dialog */
#define SIP_OFFER_CC (1 << 1) /*!< D: Offer CC on subsequent responses */
#define SIP_RINGING (1 << 2) /*!< D: Have sent 180 ringing */
#define SIP_PROGRESS_SENT (1 << 3) /*!< D: Have sent 183 message progress */
#define SIP_NEEDREINVITE (1 << 4) /*!< D: Do we need to send another reinvite? */
@ -415,7 +416,8 @@ enum subscriptiontype {
DIALOG_INFO_XML,
CPIM_PIDF_XML,
PIDF_XML,
MWI_NOTIFICATION
MWI_NOTIFICATION,
CALL_COMPLETION,
};
/*! \brief The number of media types in enum \ref media_type below. */
@ -930,6 +932,7 @@ struct sip_pvt {
AST_STRING_FIELD(url); /*!< URL to be sent with next message to peer */
AST_STRING_FIELD(parkinglot); /*!< Parkinglot */
AST_STRING_FIELD(engine); /*!< RTP engine to use */
AST_STRING_FIELD(dialstring); /*!< The dialstring used to call this SIP endpoint */
);
char via[128]; /*!< Via: header */
struct sip_socket socket; /*!< The socket used for this dialog */
@ -1066,6 +1069,8 @@ struct sip_pvt {
* The large-scale changes would be a good idea for implementing during an SDP rewrite.
*/
struct offered_media offered_media[OFFERED_MEDIA_COUNT];
struct ast_cc_config_params *cc_params;
struct sip_epa_entry *epa_entry;
};
/*! \brief sip packet - raw format for outbound packets that are sent or scheduled for transmission
@ -1197,6 +1202,7 @@ struct sip_peer {
/*XXX Seems like we suddenly have two flags with the same content. Why? To be continued... */
enum sip_peer_type type; /*!< Distinguish between "user" and "peer" types. This is used solely for CLI and manager commands */
unsigned int disallowed_methods;
struct ast_cc_config_params *cc_params;
};
/*!
@ -1286,4 +1292,359 @@ struct sip_subscription_mwi {
struct ast_dnsmgr_entry *dnsmgr; /*!< DNS refresh manager for subscription */
struct sockaddr_in us; /*!< Who the server thinks we are */
};
/*!
* SIP PUBLISH support!
* PUBLISH support was added to chan_sip due to its use in the call-completion
* event package. In order to suspend and unsuspend monitoring of a called party,
* a PUBLISH message must be sent. Rather than try to hack in PUBLISH transmission
* and reception solely for the purposes of handling call-completion-related messages,
* an effort has been made to create a generic framework for handling PUBLISH messages.
*
* There are two main components to the effort, the event publication agent (EPA) and
* the event state compositor (ESC). Both of these terms appear in RFC 3903, and the
* implementation in Asterisk conforms to the defintions there. An EPA is a UAC that
* transmits PUBLISH requests. An ESC is a UAS that receives PUBLISH requests and
* acts appropriately based on the content of those requests.
*
* ESC:
* The main structure in chan_sip is the event_state_compositor. There is an
* event_state_compositor structure for each event package supported (as of Nov 2009
* this is only the call-completion package). The structure contains data which is
* intrinsic to the event package itself, such as the name of the package and a set
* of callbacks for handling incoming PUBLISH requests. In addition, the
* event_state_compositor struct contains an ao2_container of sip_esc_entries.
*
* A sip_esc_entry corresponds to an entity which has sent a PUBLISH to Asterisk. We are
* able to match the incoming PUBLISH to a sip_esc_entry using the Sip-If-Match header
* of the message. Of course, if none is present, then a new sip_esc_entry will be created.
*
* Once it is determined what type of PUBLISH request has come in (from RFC 3903, it may
* be an initial, modify, refresh, or remove), then the event package-specific callbacks
* may be called. If your event package doesn't need to take any specific action for a
* specific PUBLISH type, it is perfectly safe to not define the callback at all. The callback
* only needs to take care of application-specific information. If there is a problem, it is
* up to the callback to take care of sending an appropriate 4xx or 5xx response code. In such
* a case, the callback should return -1. This will tell the function that called the handler
* that an appropriate error response has been sent. If the callback returns 0, however, then
* the caller of the callback will generate a new entity tag and send a 200 OK response.
*
* ESC entries are reference-counted, however as an implementor of a specific event package,
* this should be transparent, since the reference counts are handled by the general ESC
* framework.
*
* EPA:
* The event publication agent in chan_sip is structured quite a bit differently than the
* ESC. With an ESC, an appropriate entry has to be found based on the contents of an incoming
* PUBLISH message. With an EPA, the application interested in sending the PUBLISH can maintain
* a reference to the appropriate EPA entry instead. Similarly, when matching a PUBLISH response
* to an appropriate EPA entry, the sip_pvt can maintain a reference to the corresponding
* EPA entry. The result of this train of thought is that there is no compelling reason to
* maintain a container of these entries.
*
* Instead, there is only the sip_epa_entry structure. Every sip_epa_entry has an entity tag
* that it maintains so that subsequent PUBLISH requests will be identifiable by the ESC on
* the far end. In addition, there is a static_data field which contains information that is
* common to all sip_epa_entries for a specific event package. This static data includes the
* name of the event package and callbacks for handling specific responses for outgoing PUBLISHes.
* Also, there is a field for pointing to instance-specific data. This can include the current
* published state or other identifying information that is specific to an instance of an EPA
* entry of a particular event package.
*
* When an application wishes to send a PUBLISH request, it simply will call create_epa_entry,
* followed by transmit_publish in order to send the PUBLISH. That's all that is necessary.
* Like with ESC entries, sip_epa_entries are reference counted. Unlike ESC entries, though,
* sip_epa_entries reference counts have to be maintained to some degree by the application making
* use of the sip_epa_entry. The application will acquire a reference to the EPA entry when it
* calls create_epa_entry. When the application has finished using the EPA entry (which may not
* be until after several PUBLISH transactions have taken place) it must use ao2_ref to decrease
* the reference count by 1.
*/
/*!
* \brief The states that can be represented in a SIP call-completion PUBLISH
*/
enum sip_cc_publish_state {
/*! Closed, i.e. unavailable */
CC_CLOSED,
/*! Open, i.e. available */
CC_OPEN,
};
/*!
* \brief The states that can be represented in a SIP call-completion NOTIFY
*/
enum sip_cc_notify_state {
/*! Queued, i.e. unavailable */
CC_QUEUED,
/*! Ready, i.e. available */
CC_READY,
};
/*!
* \brief The types of PUBLISH messages defined in RFC 3903
*/
enum sip_publish_type {
/*!
* \brief Unknown
*
* \details
* This actually is not defined in RFC 3903. We use this as a constant
* to indicate that an incoming PUBLISH does not fit into any of the
* other categories and is thus invalid.
*/
SIP_PUBLISH_UNKNOWN,
/*!
* \brief Initial
*
* \details
* The first PUBLISH sent. This will contain a non-zero Expires header
* as well as a body that indicates the current state of the endpoint
* that has sent the message. The initial PUBLISH is the only type
* of PUBLISH to not contain a Sip-If-Match header in it.
*/
SIP_PUBLISH_INITIAL,
/*!
* \brief Refresh
*
* \details
* Used to keep a published state from expiring. This will contain a
* non-zero Expires header but no body since its purpose is not to
* update state.
*/
SIP_PUBLISH_REFRESH,
/*!
* \brief Modify
*
* \details
* Used to change state from its previous value. This will contain
* a body updating the published state. May or may not contain an
* Expires header.
*/
SIP_PUBLISH_MODIFY,
/*!
* \brief Remove
*
* \details
* Used to remove published state from an ESC. This will contain
* an Expires header set to 0 and likely no body.
*/
SIP_PUBLISH_REMOVE,
};
/*!
* Data which is the same for all instances of an EPA for a
* particular event package
*/
struct epa_static_data {
/*! The event type */
enum subscriptiontype event;
/*!
* The name of the event as it would
* appear in a SIP message
*/
const char *name;
/*!
* The callback called when a 200 OK is received on an outbound PUBLISH
*/
void (*handle_ok)(struct sip_pvt *, struct sip_request *, struct sip_epa_entry *);
/*!
* The callback called when an error response is received on an outbound PUBLISH
*/
void (*handle_error)(struct sip_pvt *, const int resp, struct sip_request *, struct sip_epa_entry *);
/*!
* Destructor to call to clean up instance data
*/
void (*destructor)(void *instance_data);
};
/*!
* \brief backend for an event publication agent
*/
struct epa_backend {
const struct epa_static_data *static_data;
AST_LIST_ENTRY(epa_backend) next;
};
struct sip_epa_entry {
/*!
* When we are going to send a publish, we need to
* know the type of PUBLISH to send.
*/
enum sip_publish_type publish_type;
/*!
* When we send a PUBLISH, we have to be
* sure to include the entity tag that we
* received in the previous response.
*/
char entity_tag[SIPBUFSIZE];
/*!
* The destination to which this EPA should send
* PUBLISHes. This may be the name of a SIP peer
* or a hostname.
*/
char destination[SIPBUFSIZE];
/*!
* The body of the most recently-sent PUBLISH message.
* This is useful for situations such as authentication,
* in which we must send a message identical to the
* one previously sent
*/
char body[SIPBUFSIZE];
/*!
* Every event package has some constant data and
* callbacks that all instances will share. This
* data resides in this field.
*/
const struct epa_static_data *static_data;
/*!
* In addition to the static data that all instances
* of sip_epa_entry will have, each instance will
* require its own instance-specific data.
*/
void *instance_data;
};
/*!
* \brief Instance data for a Call completion EPA entry
*/
struct cc_epa_entry {
/*!
* The core ID of the CC transaction
* for which this EPA entry belongs. This
* essentially acts as a unique identifier
* for the entry and is used in the hash
* and comparison functions
*/
int core_id;
/*!
* We keep the last known state of the
* device in question handy in case
* it needs to be known by a third party.
* Also, in the case where for some reason
* we get asked to transmit state that we
* already sent, we can just ignore the
* request.
*/
enum sip_cc_publish_state current_state;
};
struct event_state_compositor;
/*!
* \brief common ESC items for all event types
*
* The entity_id field serves as a means by which
* A specific entry may be found.
*/
struct sip_esc_entry {
/*!
* The name of the party who
* sent us the PUBLISH. This will more
* than likely correspond to a peer name.
*
* This field's utility isn't really that
* great. It's mainly just a user-recognizable
* handle that can be printed in debug messages.
*/
const char *device_name;
/*!
* The event package for which this esc_entry
* exists. Most of the time this isn't really
* necessary since you'll have easy access to the
* ESC which contains this entry. However, in
* some circumstances, we won't have the ESC
* available.
*/
const char *event;
/*!
* The entity ID used when corresponding
* with the EPA on the other side. As the
* ESC, we generate an entity ID for each
* received PUBLISH and store it in this
* structure.
*/
char entity_tag[30];
/*!
* The ID for the scheduler. We schedule
* destruction of a sip_esc_entry when we
* receive a PUBLISH. The destruction is
* scheduled for the duration received in
* the Expires header.
*/
int sched_id;
/*!
* Each ESC entry will be for a specific
* event type. Those entries will need to
* carry data which is intrinsic to the
* ESC entry but which is specific to
* the event package
*/
void *event_specific_data;
};
typedef int (* const esc_publish_callback)(struct sip_pvt *, struct sip_request *, struct event_state_compositor *, struct sip_esc_entry *);
/*!
* \brief Callbacks for SIP ESCs
*
* \details
* The names of the callbacks are self-explanatory. The
* corresponding handler is called whenever the specific
* type of PUBLISH is received.
*/
struct sip_esc_publish_callbacks {
const esc_publish_callback initial_handler;
const esc_publish_callback refresh_handler;
const esc_publish_callback modify_handler;
const esc_publish_callback remove_handler;
};
struct sip_cc_agent_pvt {
int offer_timer_id;
/* A copy of the original call's Call-ID.
* We use this as a search key when attempting
* to find a particular sip_pvt.
*/
char original_callid[SIPBUFSIZE];
/* A copy of the exten called originally.
* We use this to set the proper extension
* to dial during the recall since the incoming
* request URI is one that was generated just
* for the recall
*/
char original_exten[SIPBUFSIZE];
/* A reference to the dialog which we will
* be sending a NOTIFY on when it comes time
* to send one
*/
struct sip_pvt *subscribe_pvt;
/* When we send a NOTIFY, we include a URI
* that should be used by the caller when he
* wishes to send a PUBLISH or INVITE to us.
* We store that URI here.
*/
char notify_uri[SIPBUFSIZE];
/* When we advertise call completion to a caller,
* we provide a URI for the caller to use when
* he sends us a SUBSCRIBE. We store it for matching
* purposes when we receive the SUBSCRIBE from the
* caller.
*/
char subscribe_uri[SIPBUFSIZE];
char is_available;
};
struct sip_monitor_instance {
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(subscribe_uri);
AST_STRING_FIELD(notify_uri);
AST_STRING_FIELD(peername);
AST_STRING_FIELD(device_name);
);
int core_id;
struct sip_pvt *subscription_pvt;
struct sip_epa_entry *suspension_entry;
};
#endif

@ -0,0 +1,150 @@
[general]
; There is only a single option that may be defined in this file.
; The cc_max_requests option is a global limit on the number of
; CC requests that may be in the Asterisk system at any time.
;
;cc_max_requests = 20
;
;
;============================================
; PLEASE READ THIS!!!
; The options described below should NOT be
; set in this file. Rather, they should be
; set per-device in a channel driver
; configuration file.
; PLEASE READ THIS!!!
;===========================================
;
;---------------------------------------------------------------------
; Timers
;---------------------------------------------------------------------
;There are three configurable timers for all types of CC: the
;cc_offer_timer, the ccbs_available_timer, and the ccnr_available_timer.
;In addition, when using a generic agent, there is a fourth timer,
;the cc_recall_timer. All timers are configured in seconds, and the
;values shown below are the defaults.
;
;When a caller is offered CCBS or CCNR, the cc_offer_timer will
;be started. If the caller does not request CC before the
;cc_offer_timer expires, then the caller will be unable to request
;CC for this call.
;
;cc_offer_timer = 20
;
;Once a caller has requested CC, then either the ccbs_available_timer
;or the ccnr_available_timer will run, depending on the service
;requested. The reason why there are two separate timers for CCBS
;and CCNR is that it is reasonable to want to have a shorter timeout
;configured for CCBS than for CCNR. If the available timer expires
;before the called party becomes available, then the CC attempt
;will have failed and monitoring of the called party will stop.
;
;ccbs_available_timer = 4800
;ccnr_available_timer = 7200
;
; When using a generic agent, the original caller is called back
; when one of the original called parties becomes available. The
; cc_recall_timer tells Asterisk how long it should let the original
; caller's phone ring before giving up. Please note that this parameter
; only affects operation when using a generic agent.
;
;cc_recall_timer = 20
;---------------------------------------------------------------------
; Policies
;---------------------------------------------------------------------
; Policy settings tell Asterisk how to behave and what sort of
; resources to allocate in order to facilitate CC. There are two
; settings to control the actions Asterisk will take.
;
; The cc_agent_policy describes the behavior that Asterisk will
; take when communicating with the caller during CC. There are
; three possible options.
;
;never: Never offer CC to the caller. Setting the cc_agent_policy
; to this value is the way to disable CC for a call.
;
;generic: A generic CC agent is one which uses no protocol-specific
; mechanisms to offer CC to the caller. Instead, the caller
; requests CC using a dialplan function. Due to internal
; restrictions, you should only use a generic CC agent on
; phones (i.e. not "trunks"). If you are using phones which
; do not support a protocol-specific method of using CC, then
; generic CC agents are what you should use.
;
;native: A native CC agent is one which uses protocol-specific
; signaling to offer CC to the caller and accept CC requests
; from the caller. The supported protocols for native CC
; agents are SIP, ISDN ETSI PTP, ISDN ETSI PTMP, and Q.SIG
;cc_agent_policy=never
;
; The cc_monitor_policy describes the behavior that Asterisk will
; take when communicating with the called party during CC. There
; are four possible options.
;
;never: Analogous to the cc_agent_policy setting. We will never
; attempt to request CC services on this interface.
;
;generic: Analogous to the cc_agent_policy setting. We will monitor
; the called party's progress using protocol-agnostic
; capabilities. Like with generic CC agents, generic CC
; monitors should only be used for phones.
;
;native: Analogous to the cc_agent_policy setting. We will use
; protocol-specific methods to request CC from this interface
; and to monitor the interface for availability.
;
;accept: If an interface is set to "accept," then we will accept
; protocol-specific CC offers from the caller and use
; a native CC monitor for the remainder of the CC transaction.
; However, if the interface does not offer protocol-specific
; CC, then we will fall back to using a generic CC monitor
; instead. This is a good setting to use for phones for which
; you do not know if they support protocol-specific CC
; methodologies.
;cc_monitor_policy=never
;
;
;---------------------------------------------------------------------
; Limits
;---------------------------------------------------------------------
;
; The use of CC requires Asterisk to potentially use more memory than
; some administrators would like. As such, it is a good idea to limit
; the number of CC requests that can be in the system at a given time.
; The values shown below are the defaults.
;
; The cc_max_agents setting limits the number of outstanding CC
; requests a caller may have at any given time. Please note that due
; to implementation restrictions, this setting is ignored when using
; generic CC agents. Generic CC agents may only have one outstanding
; CC request.
;
;cc_max_agents = 5
;
; The cc_max_monitors setting limits the number of outstanding CC
; requests can be made to a specific interface at a given time.
;
;cc_max_monitors = 5
;
;---------------------------------------------------------------------
; Other
;---------------------------------------------------------------------
;
; When using a generic CC agent, the caller who requested CC will be
; called back when a called party becomes available. When the caller
; answers his phone, the administrator may opt to have a macro run.
; What this macro does is up to the administrator. By default there
; is no callback macro configured.
;
;cc_callback_macro=
;
; When using an ISDN phone and a generic CC agent, Asterisk is unable
; to determine the dialstring that should be used when calling back
; the original caller. Furthermore, if you desire to use any dialstring-
; specific options, such as distinctive ring, you must set this
; configuration option. For non-ISDN phones, it is not necessary to
; set this, since Asterisk can determine the dialstring to use since
; it is identical to the name of the calling device. By default, there
; is no cc_agent_dialstring set.
;
;cc_agent_dialstring=

@ -85,10 +85,11 @@
;service_message_support=yes
; Enable service message support for channel. Must be set after switchtype.
;
; PRI Reverse Charging Indication: Indicate to the called party that the
; call will be reverse charged. To enable, prefix the dialed number with one
; of the following letters:
; C - Reverse Charge Indication Requested
; Dialing options for ISDN (i.e., Dial(DAHDI/g1/exten/options)):
; R Reverse Charge Indication
; Indicate to the called party that the call will be reverse charged.
; K(n) Keypad digits n
; Send out the specified digits as keypad digits.
;
; PRI Dialplan: The ISDN-level Type Of Number (TON) or numbering plan, used for
; the dialed number. For most installations, leaving this as 'unknown' (the
@ -236,9 +237,52 @@
; May vary in other ISDN standards (Q.931 1993 : 90000 ms)
; T313: Wait for CONNECT acknowledge, CPE side only (default 3000 ms)
;
; T-RESPONSE: Maximum time to wait for a typical APDU response. (default 4000 ms)
; This is an implementation timer when the standard does not specify one.
; T-ACTIVATE: Request supervision timeout. (default 10000 ms)
; T-RETENTION: Maximum time to wait for user A to activate call-completion. (default 30000 ms)
; Used by ETSI PTP, ETSI PTMP, and Q.SIG as the cc_offer_timer.
; T-CCBS1: T-STATUS timer equivalent for CC user A status. (default 4000 ms)
; T-CCBS2: Maximum time the CCBS service will be active (default 45 min in ms)
; T-CCBS3: Maximum time to wait for user A to respond to user B availability. (default 20000 ms)
; T-CCBS5: Network B CCBS supervision timeout. (default 60 min in ms)
; T-CCBS6: Network A CCBS supervision timeout. (default 60 min in ms)
; T-CCNR2: Maximum time the CCNR service will be active (default 180 min in ms)
; T-CCNR5: Network B CCNR supervision timeout. (default 195 min in ms)
; T-CCNR6: Network A CCNR supervision timeout. (default 195 min in ms)
; CC-T1: Q.SIG CC request supervision timeout. (default 30000 ms)
; CCBS-T2: Q.SIG CCBS supervision timeout. (default 60 min in ms)
; CCNR-T2: Q.SIG CCNR supervision timeout. (default 195 min in ms)
; CC-T3: Q.SIG CC Maximum time to wait for user A to respond to user B availability. (default 30000 ms)
;
;pritimer => t200,1000
;pritimer => t313,4000
;
; CC PTMP recall mode:
; specific - Only the CC original party A can participate in the CC callback
; global - Other compatible endpoints on the PTMP line can be party A in the CC callback
;
; cc_ptmp_recall_mode cannot be changed on a reload.
;
;cc_ptmp_recall_mode = specific
;
; CC Q.SIG Party A (requester) retain signaling link option
; retain Require that the signaling link be retained.
; release Request that the signaling link be released.
; do_not_care The responder is free to choose if the signaling link will be retained.
;
;cc_qsig_signaling_link_req = retain
;
; CC Q.SIG Party B (responder) retain signaling link option
; retain Prefer that the signaling link be retained.
; release Prefer that the signaling link be released.
;
;cc_qsig_signaling_link_rsp = retain
;
; See ccss.conf.sample for more options. The timers described by ccss.conf.sample
; are not used by ISDN for the native protocol since they are defined by the
; standards and set by pritimer above.
;
; To enable transmission of facility-based ISDN supplementary services (such
; as caller name from CPE over facility), enable this option.
; Cannot be changed on a reload.
@ -267,6 +311,10 @@
; fxo_ks: FXO (Kewl Start)
; pri_cpe: PRI signalling, CPE side
; pri_net: PRI signalling, Network side
; bri_cpe: BRI PTP signalling, CPE side
; bri_net: BRI PTP signalling, Network side
; bri_cpe_ptmp: BRI PTMP signalling, CPE side
; bri_net_ptmp: BRI PTMP signalling, Network side
; sf: SF (Inband Tone) Signalling
; sf_w: SF Wink
; sf_featd: SF Feature Group D (The fake, Adtran style, DTMF)

@ -84,6 +84,7 @@ bindaddr = 0.0.0.0
; Write authorization permits you to send commands and get back responses. The
; following classes exist:
;
; all - All event classes below (including any we may have missed).
; system - General information about the system and ability to run system
; management commands, such as Shutdown, Restart, and Reload.
; call - Information about channels and ability to set information in a
@ -100,6 +101,8 @@ bindaddr = 0.0.0.0
; cdr - Output of cdr_manager, if loaded. Read-only.
; dialplan - Receive NewExten and VarSet events. Read-only.
; originate - Permission to originate new calls. Write-only.
; agi - Output AGI commands executed. Input AGI command to execute.
; cc - Call Completion events. Read-only.
;
;read = system,call,log,verbose,agent,user,config,dtmf,reporting,cdr,dialplan
;write = system,call,agent,user,config,command,reporting,originate

@ -335,6 +335,7 @@ AST_EXT_LIB_SETUP([PGSQL], [PostgreSQL], [postgres])
AST_EXT_LIB_SETUP([POPT], [popt], [popt])
AST_EXT_LIB_SETUP([PORTAUDIO], [PortAudio], [portaudio])
AST_EXT_LIB_SETUP([PRI], [ISDN PRI], [pri])
AST_EXT_LIB_SETUP_DEPENDENT([PRI_CCSS], [ISDN PRI call completion supplementary service], [PRI], [pri])
AST_EXT_LIB_SETUP_DEPENDENT([PRI_SUBADDR], [ISDN PRI subaddressing], [PRI], [pri])
AST_EXT_LIB_SETUP_DEPENDENT([PRI_CALL_HOLD], [ISDN PRI call hold], [PRI], [pri])
AST_EXT_LIB_SETUP_DEPENDENT([PRI_CALL_REROUTING], [ISDN PRI call rerouting and call deflection], [PRI], [pri])
@ -1543,6 +1544,7 @@ AST_EXT_LIB_CHECK([POPT], [popt], [poptStrerror], [popt.h])
AST_EXT_LIB_CHECK([PORTAUDIO], [portaudio], [Pa_GetDeviceCount], [portaudio.h])
AST_EXT_LIB_CHECK([PRI], [pri], [pri_connected_line_update], [libpri.h])
AST_EXT_LIB_CHECK([PRI_CCSS], [pri], [pri_cc_enable], [libpri.h])
AST_EXT_LIB_CHECK([PRI_SUBADDR], [pri], [pri_sr_set_called_subaddress], [libpri.h])
AST_EXT_LIB_CHECK([PRI_CALL_HOLD], [pri], [pri_hold_enable], [libpri.h])
AST_EXT_LIB_CHECK([PRI_CALL_REROUTING], [pri], [pri_reroute_enable], [libpri.h])

@ -147,6 +147,9 @@ reference purposes.
\chapter{Security Framework}
\input{security-events.tex}
\chapter{Call Completion Supplementary Services}
\input{ccss.tex}
\chapter{Development}
\section{Backtrace}
\input{backtrace.tex}

@ -0,0 +1,414 @@
\section{Introduction}
A new feature for Asterisk 1.8 is Call Completion Supplementary
Services. This document aims to explain the system and how to use it.
In addition, this document examines some potential troublesome points
which administrators may come across during their deployment of the
feature.
\section{What is CCSS?}
Call Completion Supplementary Services (often abbreviated "CCSS" or
simply "CC") allow for a caller to let Asterisk automatically alert him
when a called party has become available, given that a previous call to
that party failed for some reason. The two services offered are Call
Completion on Busy Subscriber (CCBS) and Call Completion on No Response
(CCNR).
To illustrate, let's say that Alice attempts to call Bob. Bob is
currently on a phone call with Carol, though, so Alice hears a busy
signal. In this situation, assuming that Asterisk has been configured
to allow for such activity, Alice would be able to request CCBS. Once
Bob has finished his phone call, Alice will be alerted. Alice can then
attempt to call Bob again.
\section{Glossary of Terms}
In this document, we will use some terms which may require
clarification. Most of these terms are specific to Asterisk, and are by
no means standard.
\begin{itemize}
\item CCBS: Call Completion on Busy Subscriber. When a call fails because the
recipient's phone is busy, the caller will have the opportunity to
request CCBS. When the recipient's phone is no longer busy, the caller
will be alerted. The means by which the caller is alerted is dependent
upon the type of agent used by the caller.
\item CCNR: Call Completion on No Response. When a call fails because the
recipient does not answer the phone, the caller will have the opportun-
ity to request CCNR. When the recipient's phone becomes busy and then
is no longer busy, the caller will be alerted. The means by which the
caller is alerted is dependent upon the type of the agent used by the
caller.
\item Agent: The agent is the entity within Asterisk that communicates with
and acts on behalf of the calling party.
\item Monitor: The monitor is the entity within Asterisk that communicates
with and monitors the status of the called party.
\item Generic Agent: A generic agent is an agent that uses protocol-agnostic
methods to communicate with the caller. Generic agents should only be
used for phones, and never should be used for "trunks."
\item Generic Monitor: A generic monitor is a monitor that uses protocol-
agnostic methods to monitor the status of the called party. Like with
generic agents, generic monitors should only be used for phones.
\item Native Agent: The opposite of a generic agent. A native agent uses
protocol-specific messages to communicate with the calling party.
Native agents may be used for both phones and trunks, but it must be
known ahead of time that the device with which Asterisk is communica-
ting supports the necessary signaling.
\item Native Monitor: The opposite of a generic monitor. A native monitor
uses protocol-specific messages to subscribe to and receive notifica-
tion of the status of the called party. Native monitors may be used
for both phones and trunks, but it must be known ahead of time that
the device with which Asterisk is communicating supports the
necessary signaling.
\item Offer: An offer of CC refers to the notification received by the caller
that he may request CC.
\item Request: When the caller decides that he would like to subscribe to CC,
he will make a request for CC. Furthermore, the term may refer to any
outstanding requests made by callers.
\item Recall: When the caller attempts to call the recipient after being
alerted that the recipient is available, this action is referred to
as a "recall."
\end{itemize}
\section{The CC Process}
\subsection{The Initial Call}
The only requirement for the use of CC is to configure an agent for
the caller and a monitor for at least one recipient of the call.
This is controlled using the cc\_agent\_policy for the caller and the
cc\_monitor\_policy for the recipient. For more information about these
configuration settings, see configs/samples/ccss.conf.sample. If the
agent for the caller is set to something other than "never" and at
least one recipient has his monitor set to something other than
"never," then CC will be offered to the caller at the end of the
call.
Once the initial call has been hung up, the configured
cc\_offer\_timer for the caller will be started. If the caller wishes to
request CC for the previous call, he must do so before the timer
expires.
\subsection{Requesting CC}
Requesting CC is done differently depending on the type of agent
the caller is using.
With generic agents, the CallCompletionRequest application must be
called in order to request CC. There are two different ways in which
this may be called. It may either be called before the caller hangs up
during the initial call, or the caller may hang up from the initial
call and dial an extension which calls the CallCompletionRequest
application. If the second method is used, then the caller will
have until the cc\_offer\_timer expires to request CC.
With native agents, the method for requesting CC is dependent upon
the technology being used, coupled with the make of equipment. It may
be possible to request CC using a programmable key on a phone or by
clicking a button on a console. If you are using equipment which can
natively support CC but do not know the means by which to request it,
then contact the equipment manufacturer for more information.
\subsection{Cancelling CC}
CC may be canceled after it has been requested. The method by which
this is accomplished differs based on the type of agent the calling
party uses.
When using a generic agent, the dialplan application
CallRequestCancel is used to cancel CC. When using a native monitor,
the method by which CC is cancelled depends on the protocol used.
Likely, this will be done using a button on a phone.
Keep in mind that if CC is cancelled, it cannot be un-cancelled.
\subsection{Monitoring the Called Party}
Once the caller has requested CC, then Asterisk's job is to monitor
the progress of the called parties. It is at this point that Asterisk
allocates the necessary resources to monitor the called parties.
A generic monitor uses Asterisk's device state subsystem in order
to determine when the called party has become available. For both CCBS
and CCNR, Asterisk simply waits for the phone's state to change to
a "not in use" state from a different state. Once this happens, then
Asterisk will consider the called party to be available and will alert
the caller.
A native monitor relies on the network to send a protocol-specific
message when the called party has become available. When Asterisk
receives such a message, it will consider the called party to be
available and will alert the caller.
Note that since a single caller may dial multiple parties, a monitor
is used for each called party. It is within reason that different called
parties will use different types of monitors for the same CC request.
\subsection{Alerting the Caller}
Once Asterisk has determined that the called party has become available
the time comes for Asterisk to alert the caller that the called party has
become available. The method by which this is done differs based on the
type of agent in use.
If a generic agent is used, then Asterisk will originate a call to
the calling party. Upon answering the call, if a callback macro has
been configured, then that macro will be executed on the calling
party's channel. After the macro has completed, an outbound call
will be issued to the parties involved in the original call.
If a native agent is used, then Asterisk will send an appropriate
notification message to the calling party to alert it that it may now
attempt its recall. How this is presented to the caller is dependent
upon the protocol and equipment that the caller is using. It is
possible that the calling party's phone will ring and a recall will
be triggered upon answering the phone, or it may be that the user
has a specific button that he may press to initiate a recall.
\subsection{If the Caller is unavailable}
When the called party has become available, it is possible that
when Asterisk attempts to alert the calling party of the called party's
availability, the calling party itself will have become unavailable.
If this is the case, then Asterisk will suspend monitoring of the
called party and will instead monitor the availability of the calling
party. The monitoring procedure for the calling party is the same
as is used in the section "Monitoring the Called Party." In other
words, the method by which the calling party is monitored is dependent
upon the type of agent used by the caller.
Once Asterisk has determined that the calling party has become
available again, Asterisk will then move back to the process used
in the section "Monitoring the Called Party."
\subsection{The CC recall}
The calling party will make its recall to the same extension
that was dialed. Asterisk will provide a channel variable,
CC\_INTERFACES, to be used as an argument to the Dial application
for CC recalls. It is strongly recommended that you use this
channel variable during a CC recall. Listed are two reasons:
\begin{itemize}
\item The dialplan may be written in such a way that the dialed
destintations are dynamically generated. With such a dialplan, it
cannot be guaranteed that the same interfaces will be recalled.
\item For calling destinations with native CC monitors, it may be
necessary to dial a special string in order to notify the channel
driver that the number being dialed is actually part of a CC recall.
\end{itemize}
Note that even if your call gets routed through local channels,
the CC\_INTERFACES variable will be populated with the appropriate
values for that specific extension.
When the called parties are dialed, it is expected that a called
party will answer, since Asterisk had previously determined that the
party was available. However, it is possible that the called party
may choose not to respond to the call, or he could have become busy
again. In such a situation, the calling party must re-request CC if
he wishes to still be alerted when the calling party has become
available.
\section{Miscellaneous Information and Tips}
\begin{itemize}
\item Be aware when using a generic agent that the max\_cc\_agents
configuration parameter is ignored. The main driving reason for
this is that the mechanism for cancelling CC when using a generic
agent would become much more potentially confusing to execute. By
limiting a calling party to having a single request, there is only
ever a single request to be cancelled, making the process simple.
\item Keep in mind that no matter what CC agent type is being used,
a CC request can only be made for the latest call issued.
\item If available timers are running on multiple called parties,
it is possible that one of the timers may expire before the others
do. If such a situation occurs, then the interface on which the
timer expired will cease to be monitored. If, though, one of the
other called parties becomes available before his available timer
expires, the called party whose available timer had previously
expired will still be included in the CC\_INTERFACES channel
variable on the recall.
\item It is strongly recommended that lots of thought is placed
into the settings of the CC timers. Our general recommendation is
that timers for phones should be set shorter than those for trunks.
The reason for this is that it makes it less likely for a link in
the middle of a network to cause CC to fail.
\item CC can potentially be a memory hog if used irresponsibly. The
following are recommendations to help curb the amount of resources
required by the CC engine. First, limit the maximum number of
CC requests in the system using the cc\_max\_requests option in
ccss.conf. Second, set the cc\_offer\_timer low for your callers. Since
it is likely that most calls will not result in a CC request, it is
a good idea to set this value to something low so that information
for calls does not stick around in memory for long. The final thing
that can be done is to conditionally set the cc\_agent\_policy to
"never" using the CALLCOMPLETION dialplan function. By doing this,
no CC information will be kept around after the call completes.
\item It is possible to request CCNR on answered calls. The reason
for this is that it is impossible to know whether a call that is
answered has actually been answered by a person or by something
such as voicemail or some other IVR.
\item Not all channel drivers have had the ability to set CC config
parameters in their configuration files added yet. At the time of
this writing (2009 Oct), only chan\_sip has had this ability added, with
short-term plans to add this to chan\_dahdi as well. It is
possible to set CC configuration parameters for other channel types,
though. For these channel types, the setting of the parameters can
only be accomplished using the CALLCOMPLETION dialplan function.
\item It is documented in many places that generic agents and monitors
can only be used for phones. In most cases, however, Asterisk has no
way of distinguishing between a phone and a trunk itself. The result
is that Asterisk will happily let you violate the advice given and
allow you to set up a trunk with a generic monitor or agent. While this
will not cause anything catastrophic to occur, the behavior will most
definitely not be what you want.
\item At the time of this writing (2009 Oct), Asterisk is the only
known SIP stack to write an implementation of
draft-ietf-bliss-call-completion-04. As a result, it is recommended
that for your SIP phones, use a generic agent and monitor. For SIP
trunks, you will only be able to use CC if the other end is
terminated by another Asterisk server running version 1.8 or later.
\item If the Dial application is called multiple times by a single
extension, CC will only be offered to the caller for the parties called
by the first instantiation of Dial.
\item If a phone forwards a call, then CC may only be requested for
the phone that executed the call forward. CC may not be requested
for the phone to which the call was forwarded.
\item CC is currently only supported by the Dial application. Queue,
Followme, and Page do not support CC because it is not particularly
useful for those applications.
\item Generic CC relies heavily on accurate device state reporting. In
particular, when using SIP phones it is vital to be sure that device
state is updated properly when using them. In order to facilitate proper
device state handling, be sure to set callcounter=yes for all peers and
to set limitonpeers=yes in the general section of sip.conf
\item When using SIP CC (i.e. native CC over SIP), it is important that
your minexpiry and maxexpiry values allow for available timers to run
as little or as long as they are configured. When an Asterisk server
requests call completion over SIP, it sends a SUBSCRIBE message with
an Expires header set to the number of seconds that the available
timer should run. If the Asterisk server that receives this SUBSCRIBE
has a maxexpiry set lower than what is in the received Expires header,
then the available timer will only run for maxexpiry seconds.
\item As with all Asterisk components, CC is not perfect. If you should
find a bug or wish to enhance the feature, please open an issue on
https://issues.asterisk.org. If writing an enhancement, please be sure
to include a patch for the enhancement, or else the issue will be
closed.
\end{itemize}
\section{Simple Example of generic call completion}
The following is an incredibly bare-bones example sip.conf
and dialplan to show basic usage of generic call completion.
It is likely that if you have a more complex setup, you will
need to make use of items like the CALLCOMPLETION dialplan
function or the CC\_INTERFACES channel variable.
First, let's establish a very simple sip.conf to use for this
\begin{verbatim}
[Mark]
context=phone_calls
cc_agent_policy=generic
cc_monitor_policy=generic
;We will accept defaults for the rest of the cc parameters
;We also are not concerned with other SIP details for this
;example
[Richard]
context=phone_calls
cc_agent_policy=generic
cc_monitor_policy=generic
\end{verbatim}
Now, let's write a simple dialplan
\begin{verbatim}
[phone_calls]
exten => 1000,1,Dial(SIP/Mark,20)
exten => 1000,n,Hangup
exten => 2000,1,Dial(SIP/Richard,20)
exten => 2000,n,Hangup
exten => 30,1,CallCompletionRequest
exten => 30,n,Hangup
exten => 31,1,CallCompletionCancel
exten => 31,n,Hangup
\end{verbatim}
\begin{itemize}
\item Scenario 1:
Mark picks up his phone and dials Richard by dialing 2000. Richard is
currently on a call, so Mark hears a busy signal. Mark then hangs up,
picks up the phone and dials 30 to call the CallCompletionRequest
application. After some time, Richard finishes his call and hangs up.
Mark is automatically called back by Asterisk. When Mark picks up his
phone, Asterisk will dial extension 2000 for him.
\item Scenario 2:
Richard picks up his phone and dials Mark by dialing 1000. Mark has stepped
away from his desk, and so he is unable to answer the phone within the
20 second dial timeout. Richard hangs up, picks the phone back up and then
dials 30 to request call completion. Mark gets back to his desk and dials
somebody's number. When Mark finishes the call, Asterisk detects that Mark's
phone has had some activity and has become available again and rings Richard's
phone. Once Richard picks up, Asterisk automatically dials exteision 1000 for
him.
\item Scenario 3:
Much like scenario 1, Mark calls Richard and Richard is busy. Mark hangs up,
picks the phone back up and then dials 30 to request call completion. After
a little while, Mark realizes he doesn't actually need to talk to Richard, so
he dials 31 to cancel call completion. When Richard becomes free, Mark will
not automatically be redialed by Asterisk.
\item Scenario 4:
Richard calls Mark, but Mark is busy. About thirty seconds later, Richard decides
that he should perhaps request call completion. However, since Richard's phone
has the default cc\_offer\_timer of 20 seconds, he has run out of time to
request call completion. He instead must attempt to dial Mark again manually. If
Mark is still busy, Richard can attempt to request call completion on this second
call instead.
\item Scenario 5:
Mark calls Richard, and Richard is busy. Mark requests call completion. Richard
does not finish his current call for another 2 hours (7200 seconds). Since Mark
has the default ccbs\_available\_timer of 4800 seconds set, Mark will not be
automatically recalled by Asterisk when Richard finishes his call.
\item Scenario 6:
Mark calls Richard, and Richard does not respond within the 20 second dial timeout.
Mark requests call completion. Richard does not use his phone again for another
4 hours (144000 seconds). Since Mark has the default ccnr\_available\_timer
of 7200 seconds set, Mark will not be automatically recalled by Asterisk when
Richard finishes his call.
\end{itemize}

@ -0,0 +1,114 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2010, Digium, Inc.
*
* Mark Michelson <mmichelson@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 Call Completion Supplementary Services implementation
* \author Mark Michelson <mmichelson@digium.com>
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/ccss.h"
#include "asterisk/pbx.h"
/*** DOCUMENTATION
<function name="CALLCOMPLETION" language="en_US">
<synopsis>
Get or set a call completion configuration parameter for a channel.
</synopsis>
<syntax>
<parameter name="option" required="true">
<para>The allowable options are:</para>
<enumlist>
<enum name="cc_agent_policy" />
<enum name="cc_monitor_policy" />
<enum name="cc_offer_timer" />
<enum name="ccnr_available_timer" />
<enum name="ccbs_available_timer" />
<enum name="cc_recall_timer" />
<enum name="cc_max_agents" />
<enum name="cc_max_monitors" />
<enum name="cc_callback_macro" />
<enum name="cc_agent_dialstring" />
</enumlist>
</parameter>
</syntax>
<description>
<para>The CALLCOMPLETION function can be used to get or set a call
completion configuration parameter for a channel. Note that setting
a configuration parameter will only change the parameter for the
duration of the call.</para>
</description>
</function>
***/
static int acf_cc_read(struct ast_channel *chan, const char *name, char *data,
char *buf, size_t buf_len)
{
struct ast_cc_config_params *cc_params;
int res;
ast_channel_lock(chan);
if (!(cc_params = ast_channel_get_cc_config_params(chan))) {
ast_channel_unlock(chan);
return -1;
}
res = ast_cc_get_param(cc_params, data, buf, buf_len);
ast_channel_unlock(chan);
return res;
}
static int acf_cc_write(struct ast_channel *chan, const char *cmd, char *data,
const char *value)
{
struct ast_cc_config_params *cc_params;
int res;
ast_channel_lock(chan);
if (!(cc_params = ast_channel_get_cc_config_params(chan))) {
ast_channel_unlock(chan);
return -1;
}
res = ast_cc_set_param(cc_params, data, value);
ast_channel_unlock(chan);
return res;
}
static struct ast_custom_function cc_function = {
.name = "CALLCOMPLETION",
.read = acf_cc_read,
.write = acf_cc_write,
};
static int unload_module(void)
{
return ast_custom_function_unregister(&cc_function);
}
static int load_module(void)
{
return ast_custom_function_register(&cc_function) == 0 ? AST_MODULE_LOAD_SUCCESS : AST_MODULE_LOAD_DECLINE;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Control Configuration Function");

File diff suppressed because it is too large Load Diff

@ -148,6 +148,8 @@ extern "C" {
#include "asterisk/linkedlists.h"
#include "asterisk/stringfields.h"
#include "asterisk/datastore.h"
#include "asterisk/channelstate.h"
#include "asterisk/ccss.h"
#define DATASTORE_INHERIT_FOREVER INT_MAX
@ -507,6 +509,29 @@ struct ast_channel_tech {
/*! \brief Get the unique identifier for the PVT, i.e. SIP call-ID for SIP */
const char * (* get_pvt_uniqueid)(struct ast_channel *chan);
/*! \brief Call a function with cc parameters as a function parameter
*
* \details
* This is a highly specialized callback that is not likely to be needed in many
* channel drivers. When dealing with a busy channel, for instance, most channel
* drivers will successfully return a channel to the requester. Once called, the channel
* can then queue a busy frame when it receives an appropriate message from the far end.
* In such a case, the channel driver has the opportunity to also queue a CC frame.
* The parameters for the CC channel can be retrieved from the channel structure.
*
* For other channel drivers, notably those that deal with "dumb" phones, the channel
* driver will not return a channel when one is requested. In such a scenario, there is never
* an opportunity for the channel driver to queue a CC frame since the channel is never
* called. Furthermore, it is not possible to retrieve the CC configuration parameters
* for the desired channel because no channel is ever allocated or returned to the
* requester. In such a case, call completion may still be a viable option. What we do is
* pass the same string that the requester used originally to request the channel to the
* channel driver. The channel driver can then find any potential channels/devices that
* match the input and return call the designated callback with the device's call completion
* parameters as a parameter.
*/
int (* cc_callback)(struct ast_channel *inbound, const char *dest, ast_cc_callback_fn callback);
};
struct ast_epoll_data;
@ -534,27 +559,6 @@ enum ast_channel_adsicpe {
AST_ADSI_OFFHOOKONLY,
};
/*!
* \brief ast_channel states
*
* \note Bits 0-15 of state are reserved for the state (up/down) of the line
* Bits 16-32 of state are reserved for flags
*/
enum ast_channel_state {
AST_STATE_DOWN, /*!< Channel is down and available */
AST_STATE_RESERVED, /*!< Channel is down, but reserved */
AST_STATE_OFFHOOK, /*!< Channel is off hook */
AST_STATE_DIALING, /*!< Digits (or equivalent) have been dialed */
AST_STATE_RING, /*!< Line is ringing */
AST_STATE_RINGING, /*!< Remote end is ringing */
AST_STATE_UP, /*!< Line is up */
AST_STATE_BUSY, /*!< Line is busy */
AST_STATE_DIALING_OFFHOOK, /*!< Digits (or equivalent) have been dialed while offhook */
AST_STATE_PRERING, /*!< Channel has detected an incoming call and is waiting for ring */
AST_STATE_MUTE = (1 << 16), /*!< Do not transmit voice data */
};
/*!
* \brief Possible T38 states on channels
*/
@ -950,9 +954,6 @@ int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore
*/
struct ast_datastore *ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid);
/*! \brief Change the state of a channel */
int ast_setstate(struct ast_channel *chan, enum ast_channel_state);
/*!
* \brief Create a channel structure
* \since 1.8
@ -2756,6 +2757,95 @@ void ast_channel_queue_redirecting_update(struct ast_channel *chan, const struct
* '0'
*/
int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int caller, int frame);
#include "asterisk/ccss.h"
/*!
* \since 1.8
* \brief Set up datastore with CCSS parameters for a channel
*
* \note
* If base_params is NULL, the channel will get the default
* values for all CCSS parameters.
*
* \details
* This function makes use of datastore operations on the channel, so
* it is important to lock the channel before calling this function.
*
* \param chan The channel to create the datastore on
* \param base_params CCSS parameters we wish to copy into the channel
* \retval 0 Success
* \retval -1 Failure
*/
int ast_channel_cc_params_init(struct ast_channel *chan,
const struct ast_cc_config_params *base_params);
/*!
* \since 1.8
* \brief Get the CCSS parameters from a channel
*
* \details
* This function makes use of datastore operations on the channel, so
* it is important to lock the channel before calling this function.
*
* \param chan Channel to retrieve parameters from
* \retval NULL Failure
* \retval non-NULL The parameters desired
*/
struct ast_cc_config_params *ast_channel_get_cc_config_params(struct ast_channel *chan);
/*!
* \since 1.8
* \brief Get a device name given its channel structure
*
* \details
* A common practice in Asterisk is to determine the device being talked
* to by dissecting the channel name. For certain channel types, this is not
* accurate. For instance, an ISDN channel is named based on what B channel is
* used, not the device being communicated with.
*
* This function interfaces with a channel tech's queryoption callback to
* retrieve the name of the device being communicated with. If the channel does not
* implement this specific option, then the traditional method of using the channel
* name is used instead.
*
* \param chan The channel to retrieve the information from
* \param device_name[out] The buffer to place the device's name into
* \param name_buffer_length The allocated space for the device_name
* \return 0 always
*/
int ast_channel_get_device_name(struct ast_channel *chan, char *device_name, size_t name_buffer_length);
/*!
* \since 1.8
* \brief Find the appropriate CC agent type to use given a channel
*
* \details
* During call completion, we will need to create a call completion agent structure. To
* figure out the type of agent to construct, we need to ask the channel driver for the
* appropriate type.
*
* Prior to adding this function, the call completion core attempted to figure this
* out for itself by stripping the technology off the channel's name. However, in the
* case of chan_dahdi, there are multiple agent types registered, and so simply searching
* for an agent type called "DAHDI" is not possible. In a case where multiple agent types
* are defined, the channel driver must have a queryoption callback defined in its
* channel_tech, and the queryoption callback must handle AST_OPTION_CC_AGENT_TYPE
*
* If a channel driver does not have a queryoption callback or if the queryoption callback
* does not handle AST_OPTION_CC_AGENT_TYPE, then the old behavior of using the technology
* portion of the channel name is used instead. This is perfectly suitable for channel drivers
* whose channel technologies are a one-to-one match with the agent types defined within.
*
* Note that this function is only called when the agent policy on a given channel is set
* to "native." Generic agents' type can be determined automatically by the core.
*
* \param chan The channel for which we wish to retrieve the agent type
* \param[out] agent_type The type of agent the channel driver wants us to use
* \param size The size of the buffer to write to
*/
int ast_channel_get_cc_agent_type(struct ast_channel *chan, char *agent_type, size_t size);
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif

@ -0,0 +1,53 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2010, Digium, Inc.
*
* 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 Channel states
* \par See also:
* \arg \ref Def_Channel
* \arg \ref channel_drivers
*/
#ifndef __AST_CHANNELSTATE_H__
#define __AST_CHANNELSTATE_H__
#include "asterisk.h"
/*!
* \brief ast_channel states
*
* \note Bits 0-15 of state are reserved for the state (up/down) of the line
* Bits 16-32 of state are reserved for flags
*/
enum ast_channel_state {
AST_STATE_DOWN, /*!< Channel is down and available */
AST_STATE_RESERVED, /*!< Channel is down, but reserved */
AST_STATE_OFFHOOK, /*!< Channel is off hook */
AST_STATE_DIALING, /*!< Digits (or equivalent) have been dialed */
AST_STATE_RING, /*!< Line is ringing */
AST_STATE_RINGING, /*!< Remote end is ringing */
AST_STATE_UP, /*!< Line is up */
AST_STATE_BUSY, /*!< Line is busy */
AST_STATE_DIALING_OFFHOOK, /*!< Digits (or equivalent) have been dialed while offhook */
AST_STATE_PRERING, /*!< Channel has detected an incoming call and is waiting for ring */
AST_STATE_MUTE = (1 << 16), /*!< Do not transmit voice data */
};
/*! \brief Change the state of a channel */
int ast_setstate(struct ast_channel *chan, enum ast_channel_state);
#endif /* __AST_CHANNELSTATE_H__ */

@ -37,7 +37,7 @@
#ifndef _ASTERISK_DEVICESTATE_H
#define _ASTERISK_DEVICESTATE_H
#include "asterisk/channel.h"
#include "asterisk/channelstate.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {

@ -324,7 +324,8 @@ enum ast_control_frame_type {
AST_CONTROL_CONNECTED_LINE = 22,/*!< Indicate connected line has changed */
AST_CONTROL_REDIRECTING = 23, /*!< Indicate redirecting id has changed */
AST_CONTROL_T38_PARAMETERS = 24, /*! T38 state change request/notification with parameters */
AST_CONTROL_SRCCHANGE = 25, /*!< Media source has changed and requires a new RTP SSRC */
AST_CONTROL_CC = 25, /*!< Indication that Call completion service is possible */
AST_CONTROL_SRCCHANGE = 26, /*!< Media source has changed and requires a new RTP SSRC */
};
enum ast_control_t38 {
@ -433,6 +434,12 @@ enum ast_control_transfer {
/*! Get or set the fax tone detection state of the channel */
#define AST_OPTION_FAX_DETECT 15
/*! Get the device name from the channel */
#define AST_OPTION_DEVICE_NAME 16
/*! Get the CC agent type from the channel */
#define AST_OPTION_CC_AGENT_TYPE 17
struct oprmode {
struct ast_channel *peer;
int mode;

@ -82,6 +82,7 @@
#define EVENT_FLAG_ORIGINATE (1 << 12) /* Originate a call to an extension */
#define EVENT_FLAG_AGI (1 << 13) /* AGI events */
#define EVENT_FLAG_HOOKRESPONSE (1 << 14) /* Hook Response */
#define EVENT_FLAG_CC (1 << 15) /* Call Completion events */
/*@} */
/*! \brief Export manager structures */

@ -70,6 +70,7 @@ extern "C" {
#endif
#include "asterisk/astobj2.h"
#include "asterisk/frame.h"
/* Maximum number of payloads supported */
#define AST_RTP_MAX_PT 256

@ -45,6 +45,14 @@ int ast_xml_finish(void);
*/
struct ast_xml_doc *ast_xml_open(char *filename);
/*! \brief Open an XML document that resides in memory.
* \param buffer The address where the document is stored
* \size The number of bytes in the document
* \retval NULL on error.
* \retval The ast_xml_doc reference to the open document.
*/
struct ast_xml_doc *ast_xml_read_memory(char *buffer, size_t size);
/*! \brief Close an already open document and free the used
* structure.
* \retval doc The document reference.
@ -90,6 +98,8 @@ const char *ast_xml_get_attribute(struct ast_xml_node *node, const char *attrnam
* \retval The node on success.
*/
struct ast_xml_node *ast_xml_find_element(struct ast_xml_node *root_node, const char *name, const char *attrname, const char *attrvalue);
struct ast_xml_ns *ast_xml_find_namespace(struct ast_xml_doc *doc, struct ast_xml_node *node, const char *ns_name);
const char *ast_xml_get_ns_href(struct ast_xml_ns *ns);
/*! \brief Get an element content string.
* \param node Node from where to get the string.

@ -140,6 +140,7 @@ int daemon(int, int); /* defined in libresolv of all places */
#include "asterisk/buildinfo.h"
#include "asterisk/xmldoc.h"
#include "asterisk/poll-compat.h"
#include "asterisk/ccss.h"
#include "asterisk/test.h"
#include "../defaults.h"
@ -3684,6 +3685,11 @@ int main(int argc, char *argv[])
exit(1);
}
if (ast_cc_init()) {
printf("%s", term_quit());
exit(1);
}
if ((moduleresult = load_modules(0))) { /* Load modules */
printf("%s", term_quit());
exit(moduleresult == -2 ? 2 : 1);

File diff suppressed because it is too large Load Diff

@ -2239,6 +2239,7 @@ int ast_hangup(struct ast_channel *chan)
}
ast_channel_unlock(chan);
ast_cc_offer(chan);
ast_manager_event(chan, EVENT_FLAG_CALL, "Hangup",
"Channel: %s\r\n"
"Uniqueid: %s\r\n"
@ -3611,6 +3612,7 @@ static int attribute_const is_visible_indication(enum ast_control_frame_type con
case AST_CONTROL_TRANSFER:
case AST_CONTROL_T38_PARAMETERS:
case _XXX_AST_CONTROL_T38:
case AST_CONTROL_CC:
break;
case AST_CONTROL_CONGESTION:
@ -3754,6 +3756,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
case AST_CONTROL_TRANSFER:
case AST_CONTROL_CONNECTED_LINE:
case AST_CONTROL_REDIRECTING:
case AST_CONTROL_CC:
/* Nothing left to do for these. */
res = 0;
break;
@ -4477,6 +4480,7 @@ struct ast_channel *__ast_request_and_dial(const char *type, format_t format, co
case AST_CONTROL_SRCCHANGE:
case AST_CONTROL_CONNECTED_LINE:
case AST_CONTROL_REDIRECTING:
case AST_CONTROL_CC:
case -1: /* Ignore -- just stopping indications */
break;
@ -7444,6 +7448,107 @@ int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struc
return retval;
}
static void *channel_cc_params_copy(void *data)
{
const struct ast_cc_config_params *src = data;
struct ast_cc_config_params *dest = ast_cc_config_params_init();
if (!dest) {
return NULL;
}
ast_cc_copy_config_params(dest, src);
return dest;
}
static void channel_cc_params_destroy(void *data)
{
struct ast_cc_config_params *cc_params = data;
ast_cc_config_params_destroy(cc_params);
}
static const struct ast_datastore_info cc_channel_datastore_info = {
.type = "Call Completion",
.duplicate = channel_cc_params_copy,
.destroy = channel_cc_params_destroy,
};
int ast_channel_cc_params_init(struct ast_channel *chan,
const struct ast_cc_config_params *base_params)
{
struct ast_cc_config_params *cc_params;
struct ast_datastore *cc_datastore;
if (!(cc_params = ast_cc_config_params_init())) {
return -1;
}
if (!(cc_datastore = ast_datastore_alloc(&cc_channel_datastore_info, NULL))) {
ast_cc_config_params_destroy(cc_params);
return -1;
}
if (base_params) {
ast_cc_copy_config_params(cc_params, base_params);
}
cc_datastore->data = cc_params;
ast_channel_datastore_add(chan, cc_datastore);
return 0;
}
struct ast_cc_config_params *ast_channel_get_cc_config_params(struct ast_channel *chan)
{
struct ast_datastore *cc_datastore;
if (!(cc_datastore = ast_channel_datastore_find(chan, &cc_channel_datastore_info, NULL))) {
/* If we can't find the datastore, it almost definitely means that the channel type being
* used has not had its driver modified to parse CC config parameters. The best action
* to take here is to create the parameters on the spot with the defaults set.
*/
if (ast_channel_cc_params_init(chan, NULL)) {
return NULL;
}
if (!(cc_datastore = ast_channel_datastore_find(chan, &cc_channel_datastore_info, NULL))) {
/* Should be impossible */
return NULL;
}
}
ast_assert(cc_datastore->data != NULL);
return cc_datastore->data;
}
int ast_channel_get_device_name(struct ast_channel *chan, char *device_name, size_t name_buffer_length)
{
int len = name_buffer_length;
char *dash;
if (!ast_channel_queryoption(chan, AST_OPTION_DEVICE_NAME, device_name, &len, 0)) {
return 0;
}
/* Dang. Do it the old-fashioned way */
ast_copy_string(device_name, chan->name, name_buffer_length);
if ((dash = strrchr(device_name, '-'))) {
*dash = '\0';
}
return 0;
}
int ast_channel_get_cc_agent_type(struct ast_channel *chan, char *agent_type, size_t size)
{
int len = size;
char *slash;
if (!ast_channel_queryoption(chan, AST_OPTION_CC_AGENT_TYPE, agent_type, &len, 0)) {
return 0;
}
ast_copy_string(agent_type, chan->name, size);
if ((slash = strchr(agent_type, '/'))) {
*slash = '\0';
}
return 0;
}
/* DO NOT PUT ADDITIONAL FUNCTIONS BELOW THIS BOUNDARY
*
* ONLY FUNCTIONS FOR PROVIDING BACKWARDS ABI COMPATIBILITY BELONG HERE

@ -980,6 +980,7 @@ static const struct permalias {
{ EVENT_FLAG_DIALPLAN, "dialplan" },
{ EVENT_FLAG_ORIGINATE, "originate" },
{ EVENT_FLAG_AGI, "agi" },
{ EVENT_FLAG_CC, "cc" },
{ INT_MAX, "all" },
{ 0, "none" },
};

@ -23,6 +23,7 @@
#include "asterisk.h"
#include "asterisk/xml.h"
#include "asterisk/logger.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
@ -67,6 +68,25 @@ struct ast_xml_doc *ast_xml_open(char *filename)
return (struct ast_xml_doc *) doc;
}
struct ast_xml_doc *ast_xml_read_memory(char *buffer, size_t size)
{
xmlDoc *doc;
if (!buffer) {
return NULL;
}
if (!(doc = xmlParseMemory(buffer, (int) size))) {
/* process xinclude elements. */
if (xmlXIncludeProcess(doc) < 0) {
xmlFreeDoc(doc);
return NULL;
}
}
return (struct ast_xml_doc *) doc;
}
void ast_xml_close(struct ast_xml_doc *doc)
{
if (!doc) {
@ -164,6 +184,16 @@ struct ast_xml_node *ast_xml_find_element(struct ast_xml_node *root_node, const
return NULL;
}
struct ast_xml_ns *ast_xml_find_namespace(struct ast_xml_doc *doc, struct ast_xml_node *node, const char *ns_name) {
xmlNsPtr ns = xmlSearchNs((xmlDocPtr) doc, (xmlNodePtr) node, (xmlChar *) ns_name);
return (struct ast_xml_ns *) ns;
}
const char *ast_xml_get_ns_href(struct ast_xml_ns *ns)
{
return (const char *) ((xmlNsPtr) ns)->href;
}
const char *ast_xml_get_text(struct ast_xml_node *node)
{
if (!node) {

Loading…
Cancel
Save