[asterisk-commits] oej: branch oej/earlyrtpfix r97624 - in /team/oej/earlyrtpfix: ./ apps/ chann...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Jan 9 14:32:12 CST 2008
Author: oej
Date: Wed Jan 9 14:32:12 2008
New Revision: 97624
URL: http://svn.digium.com/view/asterisk?view=rev&rev=97624
Log:
Reset, resolve. go.
Need to check if this branch is needed anymore, don't think this is the proper solution
to the problem.
Modified:
team/oej/earlyrtpfix/ (props changed)
team/oej/earlyrtpfix/apps/app_meetme.c
team/oej/earlyrtpfix/apps/app_queue.c
team/oej/earlyrtpfix/apps/app_voicemail.c
team/oej/earlyrtpfix/channels/chan_gtalk.c
team/oej/earlyrtpfix/channels/chan_mgcp.c
team/oej/earlyrtpfix/channels/chan_sip.c
team/oej/earlyrtpfix/channels/chan_zap.c
team/oej/earlyrtpfix/codecs/codec_zap.c
team/oej/earlyrtpfix/funcs/func_groupcount.c
team/oej/earlyrtpfix/main/asterisk.c
team/oej/earlyrtpfix/main/autoservice.c
team/oej/earlyrtpfix/main/cli.c
team/oej/earlyrtpfix/main/editline/readline.c
team/oej/earlyrtpfix/main/utils.c
team/oej/earlyrtpfix/res/res_features.c
Propchange: team/oej/earlyrtpfix/
------------------------------------------------------------------------------
automerge = http://www.codename-pineapple.org/
Propchange: team/oej/earlyrtpfix/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Wed Jan 9 14:32:12 2008
@@ -1,1 +1,1 @@
-/branches/1.4:1-96960
+/branches/1.4:1-97621
Modified: team/oej/earlyrtpfix/apps/app_meetme.c
URL: http://svn.digium.com/view/asterisk/team/oej/earlyrtpfix/apps/app_meetme.c?view=diff&rev=97624&r1=97623&r2=97624
==============================================================================
--- team/oej/earlyrtpfix/apps/app_meetme.c (original)
+++ team/oej/earlyrtpfix/apps/app_meetme.c Wed Jan 9 14:32:12 2008
@@ -1578,7 +1578,7 @@
goto outrun;
}
- retryzap = (strcasecmp(chan->tech->type, "Zap") || chan->spies ? 1 : 0);
+ retryzap = (strcasecmp(chan->tech->type, "Zap") || (chan->spies || chan->monitor) ? 1 : 0);
user->zapchannel = !retryzap;
zapretry:
@@ -1896,14 +1896,14 @@
break;
if (c) {
- if (c->fds[0] != origfd || (user->zapchannel && c->spies)) {
+ if (c->fds[0] != origfd || (user->zapchannel && (c->spies || c->monitor))) {
if (using_pseudo) {
/* Kill old pseudo */
close(fd);
using_pseudo = 0;
}
ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
- retryzap = (strcasecmp(c->tech->type, "Zap") || c->spies ? 1 : 0);
+ retryzap = (strcasecmp(c->tech->type, "Zap") || (c->spies || c->monitor) ? 1 : 0);
user->zapchannel = !retryzap;
goto zapretry;
}
Modified: team/oej/earlyrtpfix/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/team/oej/earlyrtpfix/apps/app_queue.c?view=diff&rev=97624&r1=97623&r2=97624
==============================================================================
--- team/oej/earlyrtpfix/apps/app_queue.c (original)
+++ team/oej/earlyrtpfix/apps/app_queue.c Wed Jan 9 14:32:12 2008
@@ -445,7 +445,7 @@
warned = 1;
}
}
-
+/*! \brief sets the QUEUESTATUS channel variable */
static void set_queue_result(struct ast_channel *chan, enum queue_result res)
{
int i;
@@ -508,6 +508,12 @@
QUEUE_NORMAL
};
+/*! \brief Check if members are available
+ *
+ * This function checks to see if members are available to be called. If any member
+ * is available, the function immediately returns QUEUE_NORMAL. If no members are available,
+ * the appropriate reason why is returned
+ */
static enum queue_member_status get_member_status(struct call_queue *q, int max_penalty)
{
struct member *member;
@@ -552,7 +558,7 @@
int state;
char dev[0];
};
-
+/*! \brief set a member's status based on device state of that member's interface*/
static void *handle_statechange(struct statechange *sc)
{
struct call_queue *q;
@@ -656,6 +662,7 @@
.thread = AST_PTHREADT_NULL,
};
+/*! \brief Consumer of the statechange queue */
static void *device_state_thread(void *data)
{
struct statechange *sc = NULL;
@@ -689,7 +696,7 @@
return NULL;
}
-
+/*! \brief Producer of the statechange queue */
static int statechange_queue(const char *dev, int state, void *ign)
{
struct statechange *sc;
@@ -707,7 +714,7 @@
return 0;
}
-
+/*! \brief allocate space for new queue member and set fields based on parameters passed */
static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused)
{
struct member *cur;
@@ -716,7 +723,7 @@
cur->penalty = penalty;
cur->paused = paused;
ast_copy_string(cur->interface, interface, sizeof(cur->interface));
- if(!ast_strlen_zero(membername))
+ if (!ast_strlen_zero(membername))
ast_copy_string(cur->membername, membername, sizeof(cur->membername));
else
ast_copy_string(cur->membername, interface, sizeof(cur->membername));
@@ -788,7 +795,7 @@
q->context[0] = '\0';
q->monfmt[0] = '\0';
q->periodicannouncefrequency = 0;
- if(!q->members)
+ if (!q->members)
q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
q->membercount = 0;
q->found = 1;
@@ -1246,14 +1253,14 @@
struct ast_variable *var;
int ret = -1;
- if(!(var = ast_load_realtime("queue_members", "interface", mem->interface, "queue_name", queue_name, NULL)))
+ if (!(var = ast_load_realtime("queue_members", "interface", mem->interface, "queue_name", queue_name, NULL)))
return ret;
while (var) {
- if(!strcmp(var->name, "uniqueid"))
+ if (!strcmp(var->name, "uniqueid"))
break;
var = var->next;
}
- if(var && !ast_strlen_zero(var->value)) {
+ if (var && !ast_strlen_zero(var->value)) {
if ((ast_update_realtime("queue_members", "uniqueid", var->value, field, value, NULL)) > -1)
ret = 0;
}
@@ -1775,6 +1782,11 @@
return vars;
}
+/*! \brief Part 2 of ring_one
+ *
+ * Does error checking before attempting to request a channel and call a member. This
+ * function is only called from ring_one
+ */
static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
{
int res;
@@ -1861,6 +1873,16 @@
/* Presense of ADSI CPE on outgoing channel follows ours */
tmp->chan->adsicpe = qe->chan->adsicpe;
+ /* Inherit context and extension */
+ if (!ast_strlen_zero(qe->chan->macrocontext))
+ ast_copy_string(tmp->chan->dialcontext, qe->chan->macrocontext, sizeof(tmp->chan->dialcontext));
+ else
+ ast_copy_string(tmp->chan->dialcontext, qe->chan->context, sizeof(tmp->chan->dialcontext));
+ if (!ast_strlen_zero(qe->chan->macroexten))
+ ast_copy_string(tmp->chan->exten, qe->chan->macroexten, sizeof(tmp->chan->exten));
+ else
+ ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
+
/* Place the call, but don't wait on the answer */
if ((res = ast_call(tmp->chan, location, 0))) {
/* Again, keep going even if there's an error */
@@ -1912,6 +1934,14 @@
return best;
}
+/*! \brief Place a call to a queue member
+ *
+ * Once metrics have been calculated for each member, this function is used
+ * to place a call to the appropriate member (or members). The low-level
+ * channel-handling and error detection is handled in ring_entry
+ *
+ * Returns 1 if a member was called successfully, 0 otherwise
+ */
static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
{
int ret = 0;
@@ -2044,7 +2074,16 @@
}
#define AST_MAX_WATCHERS 256
-
+/*! \brief Wait for a member to answer the call
+ *
+ * \param[in] qe the queue_ent corresponding to the caller in the queue
+ * \param[in] outgoing the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
+ * \param[in] to the amount of time (in milliseconds) to wait for a response
+ * \param[out] digit if a user presses a digit to exit the queue, this is the digit the caller pressed
+ * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
+ * \param[in] caller_disconnect if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call
+ * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
+ */
static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
{
char *queue = qe->parent->name;
@@ -2283,7 +2322,15 @@
return peer;
}
-
+/*! \brief Check if we should start attempting to call queue members
+ *
+ * The behavior of this function is dependent first on whether autofill is enabled
+ * and second on whether the ring strategy is ringall. If autofill is not enabled,
+ * then return true if we're the head of the queue. If autofill is enabled, then
+ * we count the available members and see if the number of available members is enough
+ * that given our position in the queue, we would theoretically be able to connect to
+ * one of those available members
+ */
static int is_our_turn(struct queue_ent *qe)
{
struct queue_ent *ch;
@@ -2354,7 +2401,16 @@
return res;
}
-
+/*! \brief The waiting areas for callers who are not actively calling members
+ *
+ * This function is one large loop. This function will return if a caller
+ * either exits the queue or it becomes that caller's turn to attempt calling
+ * queue members. Inside the loop, we service the caller with periodic announcements,
+ * holdtime announcements, etc. as configured in queues.conf
+ *
+ * \retval 0 if the caller's turn has arrived
+ * \retval -1 if the caller should exit the queue.
+ */
static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
{
int res = 0;
@@ -2424,6 +2480,12 @@
return 0;
}
+/*! \brief Calculate the metric of each member in the outgoing callattempts
+ *
+ * A numeric metric is given to each member depending on the ring strategy used
+ * by the queue. Members with lower metrics will be called before members with
+ * higher metrics
+ */
static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
{
if (qe->max_penalty && (mem->penalty > qe->max_penalty))
@@ -2478,6 +2540,29 @@
}
return 0;
}
+/*! \brief A large function which calls members, updates statistics, and bridges the caller and a member
+ *
+ * Here is the process of this function
+ * 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue()
+ * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this
+ * iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this
+ * member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also
+ * during each iteration, we call calc_metric to determine which members should be rung when.
+ * 3. Call ring_one to place a call to the appropriate member(s)
+ * 4. Call wait_for_answer to wait for an answer. If no one answers, return.
+ * 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered.
+ * 6. Start the monitor or mixmonitor if the option is set
+ * 7. Remove the caller from the queue to allow other callers to advance
+ * 8. Bridge the call.
+ * 9. Do any post processing after the call has disconnected.
+ *
+ * \param[in] qe the queue_ent structure which corresponds to the caller attempting to reach members
+ * \param[in] options the options passed as the third parameter to the Queue() application
+ * \param[in] url the url passed as the fourth parameter to the Queue() application
+ * \param[in,out] tries the number of times we have tried calling queue members
+ * \param[out] noption set if the call to Queue() has the 'n' option set.
+ * \param[in] agi the agi passed as the fifth parameter to the Queue() application
+ */
static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi)
{
@@ -3073,7 +3158,7 @@
if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
/* XXX future changes should beware of this assumption!! */
- if(!mem->dynamic) {
+ if (!mem->dynamic) {
res = RES_NOT_DYNAMIC;
ao2_ref(mem, -1);
ast_mutex_unlock(&q->lock);
@@ -3187,7 +3272,7 @@
if (queue_persistent_members)
dump_queue_members(q);
- if(mem->realtime)
+ if (mem->realtime)
update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
@@ -3590,6 +3675,18 @@
return 0;
}
+/*!\brief The starting point for all queue calls
+ *
+ * The process involved here is to
+ * 1. Parse the options specified in the call to Queue()
+ * 2. Join the queue
+ * 3. Wait in a loop until it is our turn to try calling a queue member
+ * 4. Attempt to call a queue member
+ * 5. If 4. did not result in a bridged call, then check for between
+ * call options such as periodic announcements etc.
+ * 6. Try 4 again uless some condition (such as an expiration time) causes us to
+ * exit the queue.
+ */
static int queue_exec(struct ast_channel *chan, void *data)
{
int res=-1;
@@ -3853,7 +3950,7 @@
lu = ast_module_user_add(chan);
- if((q = load_realtime_queue(data))) {
+ if ((q = load_realtime_queue(data))) {
ast_mutex_lock(&q->lock);
mem_iter = ao2_iterator_init(q->members, 0);
while ((m = ao2_iterator_next(&mem_iter))) {
@@ -4029,7 +4126,7 @@
use_weight=0;
/* Mark all non-realtime queues as dead for the moment */
AST_LIST_TRAVERSE(&queues, q, list) {
- if(!q->realtime) {
+ if (!q->realtime) {
q->dead = 1;
q->found = 0;
}
@@ -4070,7 +4167,7 @@
/* Check if a queue with this name already exists */
if (q->found) {
ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat);
- if(!new)
+ if (!new)
ast_mutex_unlock(&q->lock);
continue;
}
@@ -4095,7 +4192,7 @@
AST_NONSTANDARD_APP_ARGS(args, parse, ',');
interface = args.interface;
- if(!ast_strlen_zero(args.penalty)) {
+ if (!ast_strlen_zero(args.penalty)) {
tmp = args.penalty;
while (*tmp && *tmp < 33) tmp++;
penalty = atoi(tmp);
Modified: team/oej/earlyrtpfix/apps/app_voicemail.c
URL: http://svn.digium.com/view/asterisk/team/oej/earlyrtpfix/apps/app_voicemail.c?view=diff&rev=97624&r1=97623&r2=97624
==============================================================================
--- team/oej/earlyrtpfix/apps/app_voicemail.c (original)
+++ team/oej/earlyrtpfix/apps/app_voicemail.c Wed Jan 9 14:32:12 2008
@@ -2569,11 +2569,11 @@
ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
return -1;
}
- if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 2))) {
+ if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
return -1;
}
- if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 2))) {
+ if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
return -1;
}
@@ -4721,7 +4721,7 @@
stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
if (stream == NIL) {
ast_log (LOG_ERROR, "Can't connect to imap server %s\n", tmp);
- return NIL;
+ return -1;
}
get_mailbox_delimiter(stream);
/* update delimiter in imapfolder */
@@ -8805,6 +8805,7 @@
{
struct vmstate *vlist = NULL;
+ ast_mutex_lock(&vmstate_lock);
vlist = vmstates;
while (vlist) {
if (vlist->vms) {
@@ -8826,6 +8827,7 @@
}
vlist = vlist->next;
}
+ ast_mutex_unlock(&vmstate_lock);
if (option_debug > 2)
ast_log(LOG_DEBUG, "%s not found in vmstates\n",user);
return NULL;
@@ -8834,7 +8836,8 @@
static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, int interactive)
{
struct vmstate *vlist = NULL;
-
+
+ ast_mutex_lock(&vmstate_lock);
vlist = vmstates;
if (option_debug > 2)
ast_log(LOG_DEBUG, "Mailbox set to %s\n",mailbox);
@@ -8858,6 +8861,7 @@
}
vlist = vlist->next;
}
+ ast_mutex_unlock(&vmstate_lock);
if (option_debug > 2)
ast_log(LOG_DEBUG, "%s not found in vmstates\n",mailbox);
return NULL;
Modified: team/oej/earlyrtpfix/channels/chan_gtalk.c
URL: http://svn.digium.com/view/asterisk/team/oej/earlyrtpfix/channels/chan_gtalk.c?view=diff&rev=97624&r1=97623&r2=97624
==============================================================================
--- team/oej/earlyrtpfix/channels/chan_gtalk.c (original)
+++ team/oej/earlyrtpfix/channels/chan_gtalk.c Wed Jan 9 14:32:12 2008
@@ -919,6 +919,9 @@
return NULL;
}
+ /* Set CALLERID(name) to the full JID of the remote peer */
+ ast_copy_string(tmp->cid_name, tmp->them, sizeof(tmp->cid_name));
+
if(strchr(tmp->us, '/')) {
data = ast_strdupa(tmp->us);
exten = strsep(&data, "/");
@@ -940,7 +943,6 @@
int fmt;
int what;
const char *n2;
- char *data = NULL, *cid = NULL;
if (title)
n2 = title;
@@ -999,20 +1001,7 @@
ast_module_ref(ast_module_info->self);
ast_copy_string(tmp->context, client->context, sizeof(tmp->context));
ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
- /* Don't use ast_set_callerid() here because it will
- * generate a needless NewCallerID event */
- if (!strcasecmp(client->name, "guest")) {
- data = ast_strdupa(i->them);
- if (strchr(data, '/')) {
- cid = strsep(&data, "/");
- } else
- cid = data;
- } else {
- data = ast_strdupa(client->user);
- cid = data;
- }
- cid = strsep(&cid, "@");
- tmp->cid.cid_ani = ast_strdup(cid);
+
if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s"))
tmp->cid.cid_dnid = ast_strdup(i->exten);
tmp->priority = 1;
Modified: team/oej/earlyrtpfix/channels/chan_mgcp.c
URL: http://svn.digium.com/view/asterisk/team/oej/earlyrtpfix/channels/chan_mgcp.c?view=diff&rev=97624&r1=97623&r2=97624
==============================================================================
--- team/oej/earlyrtpfix/channels/chan_mgcp.c (original)
+++ team/oej/earlyrtpfix/channels/chan_mgcp.c Wed Jan 9 14:32:12 2008
@@ -434,6 +434,7 @@
static int mgcp_senddigit_begin(struct ast_channel *ast, char digit);
static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
static int mgcp_devicestate(void *data);
+static void add_header_offhook(struct mgcp_subchannel *sub, struct mgcp_request *resp);
static const struct ast_channel_tech mgcp_tech = {
.type = "MGCP",
@@ -1276,23 +1277,50 @@
static int mgcp_senddigit_begin(struct ast_channel *ast, char digit)
{
- /* Let asterisk play inband indications */
- return -1;
+ struct mgcp_subchannel *sub = ast->tech_pvt;
+ struct mgcp_endpoint *p = sub->parent;
+ int res = 0;
+
+ ast_mutex_lock(&sub->lock);
+ if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
+ ast_log(LOG_DEBUG, "Sending DTMF using inband/hybrid\n");
+ res = -1; /* Let asterisk play inband indications */
+ } else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
+ ast_log(LOG_DEBUG, "Sending DTMF using RFC2833");
+ ast_rtp_senddigit_begin(sub->rtp, digit);
+ } else {
+ ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
+ }
+ ast_mutex_unlock(&sub->lock);
+
+ return res;
}
static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
{
struct mgcp_subchannel *sub = ast->tech_pvt;
+ struct mgcp_endpoint *p = sub->parent;
+ int res = 0;
char tmp[4];
- tmp[0] = 'D';
- tmp[1] = '/';
- tmp[2] = digit;
- tmp[3] = '\0';
ast_mutex_lock(&sub->lock);
- transmit_notify_request(sub, tmp);
+ if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
+ ast_log(LOG_DEBUG, "Stopping DTMF using inband/hybrid\n");
+ res = -1; /* Tell Asterisk to stop inband indications */
+ } else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
+ ast_log(LOG_DEBUG, "Stopping DTMF using RFC2833\n");
+ tmp[0] = 'D';
+ tmp[1] = '/';
+ tmp[2] = digit;
+ tmp[3] = '\0';
+ transmit_notify_request(sub, tmp);
+ ast_rtp_senddigit_end(sub->rtp, digit);
+ } else {
+ ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
+ }
ast_mutex_unlock(&sub->lock);
- return -1; /* Return non-zero so that Asterisk will stop the inband indications */
+
+ return res;
}
/*!
@@ -2193,7 +2221,7 @@
add_header(&resp, "R", "L/hd(N)");
break;
case MGCP_OFFHOOK:
- add_header(&resp, "R", (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N),L/hf(N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)");
+ add_header_offhook(sub, &resp);
break;
}
if (!ast_strlen_zero(tone)) {
@@ -2236,7 +2264,7 @@
add_header(&resp, "R", "L/hd(N)");
break;
case MGCP_OFFHOOK:
- add_header(&resp, "R", (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N),L/hf(N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)");
+ add_header_offhook(sub, &resp);
break;
}
if (!ast_strlen_zero(tone2)) {
@@ -2277,7 +2305,7 @@
add_header(&resp, "R", "L/hd(N)");
break;
case MGCP_OFFHOOK:
- add_header(&resp, "R", (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N), L/hf(N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)");
+ add_header_offhook(sub, &resp);
break;
}
/* fill in new fields */
@@ -2286,6 +2314,16 @@
return send_request(p, sub, &resp, oseq); /* SC */
}
+
+static void add_header_offhook(struct mgcp_subchannel *sub, struct mgcp_request *resp)
+{
+ struct mgcp_endpoint *p = sub->parent;
+
+ if (p && p->sub && p->sub->owner && p->sub->owner->_state >= AST_STATE_RINGING && (p->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)))
+ add_header(resp, "R", "L/hu(N),L/hf(N)");
+ else
+ add_header(resp, "R", "L/hu(N),L/hf(N),D/[0-9#*](N)");
+}
static int transmit_audit_endpoint(struct mgcp_endpoint *p)
{
Modified: team/oej/earlyrtpfix/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/oej/earlyrtpfix/channels/chan_sip.c?view=diff&rev=97624&r1=97623&r2=97624
==============================================================================
--- team/oej/earlyrtpfix/channels/chan_sip.c (original)
+++ team/oej/earlyrtpfix/channels/chan_sip.c Wed Jan 9 14:32:12 2008
@@ -150,6 +150,7 @@
#include "asterisk/threadstorage.h"
#include "asterisk/translate.h"
#include "asterisk/dnsmgr.h"
+#include "asterisk/astobj2.h"
#ifndef FALSE
#define FALSE 0
@@ -1011,7 +1012,7 @@
struct ast_rtp *remotertp; /*!< Remote RTP Session (for direct RTP setup) */
struct ast_rtp *remotevrtp; /*!< Remote Video RTP session (for direct RTP setup) */
- struct sip_pkt *packets; /*!< Packets scheduled for re-transmission */
+ struct ao2_container *packets; /*!< Packets scheduled for re-transmission */
struct sip_history_head *history; /*!< History of this SIP dialog */
size_t history_entries; /*!< Number of entires in the history */
struct ast_variable *chanvars; /*!< Channel variables to set for inbound call */
@@ -1028,7 +1029,6 @@
/*! \brief sip packet - raw format for outbound packets that are sent or scheduled for transmission */
struct sip_pkt {
- struct sip_pkt *next; /*!< Next packet in linked list */
int retrans; /*!< Retransmission number */
int method; /*!< SIP method for this packet */
int seqno; /*!< Sequence number */
@@ -1856,7 +1856,7 @@
if (!(hist = ast_calloc(1, sizeof(*hist) + l)))
return;
if (!p->history && !(p->history = ast_calloc(1, sizeof(*p->history)))) {
- free(hist);
+ ast_free(hist);
return;
}
memcpy(hist->event, buf, l);
@@ -1893,12 +1893,15 @@
/*! \brief Retransmit SIP message if no answer (Called from scheduler) */
static int retrans_pkt(const void *data)
{
- struct sip_pkt *pkt = (struct sip_pkt *)data, *prev, *cur = NULL;
+ struct sip_pkt *pkt = (struct sip_pkt *)data, *prev;
int reschedule = DEFAULT_RETRANS;
int xmitres = 0;
+ ao2_ref(pkt, 1); /* Make sure this cannot go away while we're using it */
+
/* Lock channel PVT */
- ast_mutex_lock(&pkt->owner->lock);
+ if (pkt->owner)
+ ast_mutex_lock(&pkt->owner->lock);
if (pkt->retrans < MAX_RETRANS) {
pkt->retrans++;
@@ -1926,7 +1929,7 @@
ast_log(LOG_DEBUG, "** SIP timers: Rescheduling retransmission %d to %d ms (t1 %d ms (Retrans id #%d)) \n", pkt->retrans +1, siptimer_a, pkt->timer_t1, pkt->retransid);
}
- if (sip_debug_test_pvt(pkt->owner)) {
+ if (pkt->owner && sip_debug_test_pvt(pkt->owner)) {
const struct sockaddr_in *dst = sip_real_dst(pkt->owner);
ast_verbose("Retransmitting #%d (%s) to %s:%d:\n%s\n---\n",
pkt->retrans, sip_nat_mode(pkt->owner),
@@ -1936,38 +1939,43 @@
append_history(pkt->owner, "ReTx", "%d %s", reschedule, pkt->data);
xmitres = __sip_xmit(pkt->owner, pkt->data, pkt->packetlen);
- ast_mutex_unlock(&pkt->owner->lock);
+ if (pkt->owner)
+ ast_mutex_unlock(&pkt->owner->lock);
if (xmitres == XMIT_ERROR)
- ast_log(LOG_WARNING, "Network error on retransmit in dialog %s\n", pkt->owner->callid);
- else
+ ast_log(LOG_WARNING, "Network error on retransmit in dialog %s\n", pkt->owner ? pkt->owner->callid : "<unknown>");
+ else {
+ ao2_ref(pkt, -1);
return reschedule;
+ }
}
/* Too many retries */
if (pkt->owner && pkt->method != SIP_OPTIONS && xmitres == 0) {
if (ast_test_flag(pkt, FLAG_FATAL) || sipdebug) /* Tell us if it's critical or if we're debugging */
ast_log(LOG_WARNING, "Maximum retries exceeded on transmission %s for seqno %d (%s %s)\n", pkt->owner->callid, pkt->seqno, (ast_test_flag(pkt, FLAG_FATAL)) ? "Critical" : "Non-critical", (ast_test_flag(pkt, FLAG_RESPONSE)) ? "Response" : "Request");
- } else if ((pkt->method == SIP_OPTIONS) && sipdebug) {
- ast_log(LOG_WARNING, "Cancelling retransmit of OPTIONs (call id %s) \n", pkt->owner->callid);
- }
- if (xmitres == XMIT_ERROR) {
- ast_log(LOG_WARNING, "Transmit error :: Cancelling transmission of transaction in call id %s \n", pkt->owner->callid);
- append_history(pkt->owner, "XmitErr", "%s", (ast_test_flag(pkt, FLAG_FATAL)) ? "(Critical)" : "(Non-critical)");
- } else
- append_history(pkt->owner, "MaxRetries", "%s", (ast_test_flag(pkt, FLAG_FATAL)) ? "(Critical)" : "(Non-critical)");
-
+ } else if (pkt->owner && (pkt->method == SIP_OPTIONS) && sipdebug) {
+ ast_log(LOG_WARNING, "Cancelling retransmit of OPTIONs (call id %s) \n", pkt->owner->callid);
+ }
+ if (pkt->owner) {
+ if (xmitres == XMIT_ERROR) {
+ ast_log(LOG_WARNING, "Transmit error :: Cancelling transmission of transaction in call id %s \n", pkt->owner->callid);
+ append_history(pkt->owner, "XmitErr", "%s", (ast_test_flag(pkt, FLAG_FATAL)) ? "(Critical)" : "(Non-critical)");
+ } else
+ append_history(pkt->owner, "MaxRetries", "%s", (ast_test_flag(pkt, FLAG_FATAL)) ? "(Critical)" : "(Non-critical)");
+ }
pkt->retransid = -1;
if (ast_test_flag(pkt, FLAG_FATAL)) {
- while(pkt->owner->owner && ast_channel_trylock(pkt->owner->owner)) {
+ while (pkt->owner && pkt->owner->owner && ast_channel_trylock(pkt->owner->owner)) {
ast_mutex_unlock(&pkt->owner->lock); /* SIP_PVT, not channel */
usleep(1);
- ast_mutex_lock(&pkt->owner->lock);
- }
-
- if (pkt->owner->owner && !pkt->owner->owner->hangupcause)
+ if (pkt->owner)
+ ast_mutex_lock(&pkt->owner->lock);
+ }
+
+ if (pkt->owner && pkt->owner->owner && !pkt->owner->owner->hangupcause)
pkt->owner->owner->hangupcause = AST_CAUSE_NO_USER_RESPONSE;
- if (pkt->owner->owner) {
+ if (pkt->owner && pkt->owner->owner) {
sip_alreadygone(pkt->owner);
ast_log(LOG_WARNING, "Hanging up call %s - no reply to our critical packet.\n", pkt->owner->callid);
ast_queue_hangup(pkt->owner->owner);
@@ -1976,7 +1984,7 @@
/* If no channel owner, destroy now */
/* Let the peerpoke system expire packets when the timer expires for poke_noanswer */
- if (pkt->method != SIP_OPTIONS) {
+ if (pkt->owner && pkt->method != SIP_OPTIONS) {
ast_set_flag(&pkt->owner->flags[0], SIP_NEEDDESTROY);
sip_alreadygone(pkt->owner);
if (option_debug)
@@ -1985,7 +1993,7 @@
}
}
- if (pkt->method == SIP_BYE) {
+ if (pkt->owner && pkt->method == SIP_BYE) {
/* We're not getting answers on SIP BYE's. Tear down the call anyway. */
if (pkt->owner->owner)
ast_channel_unlock(pkt->owner->owner);
@@ -1994,23 +2002,23 @@
}
/* In any case, go ahead and remove the packet */
- for (prev = NULL, cur = pkt->owner->packets; cur; prev = cur, cur = cur->next) {
- if (cur == pkt)
- break;
- }
- if (cur) {
- if (prev)
- prev->next = cur->next;
- else
- pkt->owner->packets = cur->next;
+ if (pkt->owner && (prev = ao2_find(pkt->owner->packets, pkt, OBJ_UNLINK | OBJ_POINTER))) {
+ /* Destroy the container's reference (inherited) */
+ ao2_ref(prev, -1);
ast_mutex_unlock(&pkt->owner->lock);
- free(cur);
- pkt = NULL;
- } else
+ /* Now destroy our initial reference */
+ ao2_ref(pkt, -1);
+ /* And destroy the sched ref */
+ ao2_ref(pkt, -1);
+ return 0;
+ } else {
ast_log(LOG_WARNING, "Weird, couldn't find packet owner!\n");
- if (pkt)
- ast_mutex_unlock(&pkt->owner->lock);
- return 0;
+ if (pkt->owner)
+ ast_mutex_unlock(&pkt->owner->lock);
+ ao2_ref(pkt, -1); /* Initial ref */
+ ao2_ref(pkt, -1); /* Sched ref */
+ return 0;
+ }
}
/*! \brief Transmit packet with retransmits
@@ -2022,12 +2030,11 @@
int siptimer_a = DEFAULT_RETRANS;
int xmitres = 0;
- if (!(pkt = ast_calloc(1, sizeof(*pkt) + len + 1)))
+ if (!(pkt = ao2_alloc(sizeof(*pkt) + len + 1, ast_free)))
return AST_FAILURE;
memcpy(pkt->data, data, len);
pkt->method = sipmethod;
pkt->packetlen = len;
- pkt->next = p->packets;
pkt->owner = p;
pkt->seqno = seqno;
if (resp)
@@ -2039,12 +2046,9 @@
if (pkt->timer_t1)
siptimer_a = pkt->timer_t1 * 2;
- /* Schedule retransmission */
- pkt->retransid = ast_sched_add_variable(sched, siptimer_a, retrans_pkt, pkt, 1);
if (option_debug > 3 && sipdebug)
ast_log(LOG_DEBUG, "*** SIP TIMER: Initializing retransmit timer on packet: Id #%d\n", pkt->retransid);
- pkt->next = p->packets;
- p->packets = pkt;
+
if (sipmethod == SIP_INVITE) {
/* Note this is a pending invite */
p->pendinginvite = seqno;
@@ -2054,11 +2058,25 @@
if (xmitres == XMIT_ERROR) { /* Serious network trouble, no need to try again */
append_history(pkt->owner, "XmitErr", "%s", (ast_test_flag(pkt, FLAG_FATAL)) ? "(Critical)" : "(Non-critical)");
- ast_sched_del(sched, pkt->retransid); /* No more retransmission */
pkt->retransid = -1;
+ ao2_ref(pkt, -1); /* and deallocate */
return AST_FAILURE;
- } else
+ } else {
+ /* Add refcount for scheduler pointer */
+ ao2_ref(pkt, 1);
+ /* Schedule retransmission */
+ pkt->retransid = ast_sched_add_variable(sched, siptimer_a, retrans_pkt, pkt, 1);
+ /* Link into the list of packets */
+ ao2_link(p->packets, pkt);
return AST_SUCCESS;
+ }
+}
+
+static int __deref_ao2_owner_cb(void *obj, void *unused, int flags)
+{
+ struct sip_pkt *pkt = obj;
+ pkt->owner = NULL;
+ return 0;
}
/*! \brief Kill a SIP dialog (called by scheduler) */
@@ -2072,16 +2090,15 @@
p->subscribed = NONE;
append_history(p, "Subscribestatus", "timeout");
if (option_debug > 2)
- ast_log(LOG_DEBUG, "Re-scheduled destruction of SIP subsription %s\n", p->callid ? p->callid : "<unknown>");
+ ast_log(LOG_DEBUG, "Re-scheduled destruction of SIP subscription %s\n", p->callid ? p->callid : "<unknown>");
return 10000; /* Reschedule this destruction so that we know that it's gone */
}
- /* If there are packets still waiting for delivery, delay the destruction */
- if (p->packets) {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Re-scheduled destruction of SIP call %s\n", p->callid ? p->callid : "<unknown>");
- append_history(p, "ReliableXmit", "timeout");
- return 10000;
+ /* If there are packets still waiting for delivery, make sure they can't callback to us anymore. */
+ if (ao2_container_count(p->packets)) {
+ ast_mutex_lock(&p->lock);
+ ao2_callback(p->packets, 0, __deref_ao2_owner_cb, NULL);
+ ast_mutex_unlock(&p->lock);
}
/* If we're destroying a subscription, dereference peer object too */
@@ -2138,7 +2155,8 @@
/*! \brief Acknowledges receipt of a packet and stops retransmission */
static void __sip_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod)
{
- struct sip_pkt *cur, *prev = NULL;
+ struct sip_pkt *cur;
+ struct ao2_iterator ao2i;
/* Just in case... */
char *msg;
@@ -2147,7 +2165,8 @@
msg = sip_methods[sipmethod].text;
ast_mutex_lock(&p->lock);
- for (cur = p->packets; cur; prev = cur, cur = cur->next) {
+ ao2i = ao2_iterator_init(p->packets, 0);
+ while ((cur = ao2_iterator_next(&ao2i))) {
if ((cur->seqno == seqno) && ((ast_test_flag(cur, FLAG_RESPONSE)) == resp) &&
((ast_test_flag(cur, FLAG_RESPONSE)) ||
(!strncasecmp(msg, cur->data, strlen(msg)) && (cur->data[strlen(msg)] < 33)))) {
@@ -2158,59 +2177,68 @@
}
/* this is our baby */
res = TRUE;
- UNLINK(cur, p->packets, prev);
if (cur->retransid > -1) {
if (sipdebug && option_debug > 3)
ast_log(LOG_DEBUG, "** SIP TIMER: Cancelling retransmit of packet (reply received) Retransid #%d\n", cur->retransid);
- ast_sched_del(sched, cur->retransid);
+ if (!ast_sched_del(sched, cur->retransid))
+ ao2_ref(cur, -1); /* scheduler deref */
cur->retransid = -1;
}
- free(cur);
+
+ /* Remove it from the list */
+ ao2_unlink(p->packets, cur);
+ ao2_ref(cur, -1); /* iterator deref */
break;
}
+
+ ao2_ref(cur, -1); /* iterator deref */
}
ast_mutex_unlock(&p->lock);
if (option_debug)
ast_log(LOG_DEBUG, "Stopping retransmission on '%s' of %s %d: Match %s\n", p->callid, resp ? "Response" : "Request", seqno, res ? "Not Found" : "Found");
}
-/*! \brief Pretend to ack all packets
- * maybe the lock on p is not strictly necessary but there might be a race */
+static int __sip_pretend_ack_cb(void *obj, void *vp, int flags)
+{
+ struct sip_pvt *p = vp;
+ struct sip_pkt *pkt = obj;
+ __sip_ack(p, pkt->seqno, ast_test_flag(pkt, FLAG_RESPONSE), pkt->method ? pkt->method : find_sip_method(pkt->data));
+ return 0;
+}
+
+/*! \brief Pretend to ack all packets */
static void __sip_pretend_ack(struct sip_pvt *p)
{
- struct sip_pkt *cur = NULL;
-
- while (p->packets) {
- int method;
- if (cur == p->packets) {
- ast_log(LOG_WARNING, "Have a packet that doesn't want to give up! %s\n", sip_methods[cur->method].text);
- return;
- }
- cur = p->packets;
- method = (cur->method) ? cur->method : find_sip_method(cur->data);
- __sip_ack(p, cur->seqno, ast_test_flag(cur, FLAG_RESPONSE), method);
- }
+ ao2_callback(p->packets, 0, __sip_pretend_ack_cb, p);
}
/*! \brief Acks receipt of packet, keep it around (used for provisional responses) */
static int __sip_semi_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod)
{
- struct sip_pkt *cur;
+ struct sip_pkt *cur, *found;
int res = -1;
-
- for (cur = p->packets; cur; cur = cur->next) {
+ struct ao2_iterator ao2i;
+
+ ao2i = ao2_iterator_init(p->packets, 0);
+ while ((cur = ao2_iterator_next(&ao2i))) {
if (cur->seqno == seqno && ast_test_flag(cur, FLAG_RESPONSE) == resp &&
(ast_test_flag(cur, FLAG_RESPONSE) || method_match(sipmethod, cur->data))) {
/* this is our baby */
if (cur->retransid > -1) {
if (option_debug > 3 && sipdebug)
ast_log(LOG_DEBUG, "*** SIP TIMER: Cancelling retransmission #%d - %s (got response)\n", cur->retransid, sip_methods[sipmethod].text);
- ast_sched_del(sched, cur->retransid);
+ if (!ast_sched_del(sched, cur->retransid))
+ ao2_ref(cur, -1); /* scheduler deref */
cur->retransid = -1;
}
res = 0;
+ /* Now remove it from the packet list. */
+ if ((found = ao2_find(p->packets, cur, OBJ_UNLINK | OBJ_POINTER)))
+ ao2_ref(found, -1); /* container item deref */
+ ao2_ref(cur, -1); /* iterator deref */
break;
}
+ ao2_ref(cur, -1); /* iterator deref */
}
if (option_debug)
ast_log(LOG_DEBUG, "(Provisional) Stopping retransmission (but retaining packet) on '%s' %s %d: %s\n", p->callid, resp ? "Response" : "Request", seqno, res ? "Not Found" : "Found");
@@ -3049,11 +3077,21 @@
}
+static int __sip_destroy_packet_cb(void *obj, void *unused, int flags)
+{
+ struct sip_pkt *pkt = obj;
+ if (pkt->retransid > -1) {
+ if (!ast_sched_del(sched, pkt->retransid))
+ ao2_ref(pkt, -1); /* scheduler deref */
+ }
+ pkt->owner = NULL;
+ return 0;
+}
+
/*! \brief Execute destruction of SIP dialog structure, release memory */
static void __sip_destroy(struct sip_pvt *p, int lockowner)
{
struct sip_pvt *cur, *prev = NULL;
- struct sip_pkt *cp;
if (sip_debug_test_pvt(p) || option_debug > 2)
ast_verbose("Really destroying SIP dialog '%s' Method: %s\n", p->callid, sip_methods[p->method].text);
@@ -3072,7 +3110,7 @@
sip_dump_history(p);
if (p->options)
- free(p->options);
+ ast_free(p->options);
if (p->stateid > -1)
ast_extension_state_del(p->stateid, NULL);
@@ -3090,7 +3128,7 @@
if (p->udptl)
ast_udptl_destroy(p->udptl);
if (p->refer)
- free(p->refer);
+ ast_free(p->refer);
if (p->route) {
free_old_route(p->route);
p->route = NULL;
@@ -3115,7 +3153,7 @@
if (p->history) {
struct sip_history *hist;
while ( (hist = AST_LIST_REMOVE_HEAD(p->history, list)) ) {
- free(hist);
+ ast_free(hist);
p->history_entries--;
}
free(p->history);
@@ -3134,12 +3172,8 @@
}
/* remove all current packets in this dialog */
- while((cp = p->packets)) {
- p->packets = p->packets->next;
- if (cp->retransid > -1)
- ast_sched_del(sched, cp->retransid);
- free(cp);
- }
+ ao2_callback(p->packets, 0, __sip_destroy_packet_cb, NULL);
+
if (p->chanvars) {
ast_variables_destroy(p->chanvars);
p->chanvars = NULL;
@@ -3148,7 +3182,7 @@
ast_string_field_free_memory(p);
- free(p);
+ ast_free(p);
}
/*! \brief update_call_counter: Handle call_limit for SIP users
@@ -4399,17 +4433,40 @@
snprintf(tagbuf, len, "as%08lx", ast_random());
}
+static int packet_hash_fn(const void *obj, const int flags)
+{
+ const struct sip_pkt *pkt = obj;
+ return pkt->seqno;
+}
+
+static int packet_cmp_fn(void *obj1, void *obj2, int flags)
+{
+ struct sip_pkt *p1 = obj1, *p2 = obj2;
+
+ if (flags & OBJ_POINTER)
+ return p1 == p2 ? CMP_MATCH : 0;
+ else
+ return p1->seqno == p2->seqno ? CMP_MATCH : 0;
+}
+
/*! \brief Allocate SIP_PVT structure and set defaults */
static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin,
int useglobal_nat, const int intended_method)
{
struct sip_pvt *p;
-
- if (!(p = ast_calloc(1, sizeof(*p))))
+ struct ao2_container *aoc;
+
+ if (!(aoc = ao2_container_alloc(37, packet_hash_fn, packet_cmp_fn)))
return NULL;
+ if (!(p = ast_calloc(1, sizeof(*p)))) {
+ ao2_ref(aoc, -1);
+ return NULL;
+ }
+
if (ast_string_field_init(p, 512)) {
- free(p);
+ ao2_ref(aoc, -1);
+ ast_free(p);
return NULL;
}
@@ -4422,6 +4479,7 @@
p->subscribed = NONE;
p->stateid = -1;
p->prefs = default_prefs; /* Set default codecs for this call */
+ p->packets = aoc;
if (intended_method != SIP_OPTIONS) /* Peerpoke has it's own system */
p->timer_t1 = 500; /* Default SIP retransmission timer T1 (RFC 3261) */
@@ -15588,7 +15646,7 @@
}
}
/* If we have sessions that needs to be destroyed, do it now */
- if (ast_test_flag(&sip->flags[0], SIP_NEEDDESTROY) && !sip->packets &&
+ if (ast_test_flag(&sip->flags[0], SIP_NEEDDESTROY) && !ao2_container_count(sip->packets) &&
!sip->owner) {
ast_mutex_unlock(&sip->lock);
__sip_destroy(sip, 1);
Modified: team/oej/earlyrtpfix/channels/chan_zap.c
URL: http://svn.digium.com/view/asterisk/team/oej/earlyrtpfix/channels/chan_zap.c?view=diff&rev=97624&r1=97623&r2=97624
==============================================================================
[... 379 lines stripped ...]
More information about the asterisk-commits
mailing list