aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b>2009-03-30 15:23:59 +0000
committermmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b>2009-03-30 15:23:59 +0000
commit6cc79ca03ba49de2df2e9f43501019f037dc70c6 (patch)
tree62df1ead95e6307db5ff472a49400931cc19e9ee
parent6fb02188ab3f001aa0e07c5efb09dc12ee4d8b86 (diff)
Backport state interface changes to app_queue from trunk.
After several issues raised on the Asterisk bugtracker against the 1.4 branch were determined to be fixable with the state interface change available in the 1.6.X series, it finally came time to just suck it up and backport the change. For a detailed explanation of what this change entails, the original trunk commit for this feature may be found here: http://svn.digium.com/view/asterisk?view=revision&revision=97203 In addition, the details for the use of this change to fix the problems stated in issue #12970 may be found in the review request I made for this change. It is linked below. (closes issue #12970) Reported by: edugs15 Review: http://reviewboard.digium.com/r/116 git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@184980 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--apps/app_queue.c127
-rw-r--r--configs/queues.conf.sample6
2 files changed, 88 insertions, 45 deletions
diff --git a/apps/app_queue.c b/apps/app_queue.c
index efb789ebe..e04a819a4 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -192,7 +192,7 @@ static char *descrip =
static char *app_aqm = "AddQueueMember" ;
static char *app_aqm_synopsis = "Dynamically adds queue members" ;
static char *app_aqm_descrip =
-" AddQueueMember(queuename[|interface[|penalty[|options[|membername]]]]):\n"
+" AddQueueMember(queuename[|interface[|penalty[|options[|membername[|state_interface]]]]]):\n"
"Dynamically adds interface to an existing queue.\n"
"If the interface is already in the queue and there exists an n+101 priority\n"
"then it will then jump to this priority. Otherwise it will return an error\n"
@@ -202,6 +202,9 @@ static char *app_aqm_descrip =
" AQMSTATUS The status of the attempt to add a queue member as a \n"
" text string, one of\n"
" ADDED | MEMBERALREADY | NOSUCHQUEUE \n"
+"If a device is provided in the state_interface parameter, then this will\n"
+"be the device which will be used to determine the device state of the\n"
+"added queue member.\n"
"Example: AddQueueMember(techsupport|SIP/3000)\n"
"";
@@ -354,6 +357,7 @@ struct queue_ent {
struct member {
char interface[80]; /*!< Technology/Location */
+ char state_interface[80]; /*!< Technology/Location from which to read device state changes */
char membername[80]; /*!< Member name to use in queue logs */
int penalty; /*!< Are we a last resort? */
int calls; /*!< Number of calls serviced by this member */
@@ -598,7 +602,7 @@ static int update_status(const char *interface, const int status)
while ((cur = ao2_iterator_next(&mem_iter))) {
char *tmp_interface;
char *slash_pos;
- tmp_interface = ast_strdupa(cur->interface);
+ tmp_interface = ast_strdupa(cur->state_interface);
if ((slash_pos = strchr(tmp_interface, '/')))
if ((slash_pos = strchr(slash_pos + 1, '/')))
*slash_pos = '\0';
@@ -751,7 +755,7 @@ static int statechange_queue(const char *dev, int state, void *ign)
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)
+static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface)
{
struct member *cur;
@@ -759,13 +763,18 @@ static struct member *create_queue_member(const char *interface, const char *mem
cur->penalty = penalty;
cur->paused = paused;
ast_copy_string(cur->interface, interface, sizeof(cur->interface));
+ if (!ast_strlen_zero(state_interface)) {
+ ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
+ } else {
+ ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
+ }
if (!ast_strlen_zero(membername))
ast_copy_string(cur->membername, membername, sizeof(cur->membername));
else
ast_copy_string(cur->membername, interface, sizeof(cur->membername));
if (!strchr(cur->interface, '/'))
ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
- cur->status = ast_device_state(interface);
+ cur->status = ast_device_state(cur->state_interface);
}
return cur;
@@ -899,17 +908,21 @@ static int add_to_interfaces(const char *interface)
static int interface_exists_global(const char *interface)
{
struct call_queue *q;
- struct member *mem, tmpmem;
+ struct member *mem;
+ struct ao2_iterator mem_iter;
int ret = 0;
- ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
-
AST_LIST_LOCK(&queues);
AST_LIST_TRAVERSE(&queues, q, list) {
ast_mutex_lock(&q->lock);
- if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
+ mem_iter = ao2_iterator_init(q->members, 0);
+ while ((mem = ao2_iterator_next(&mem_iter))) {
+ if (!strcasecmp(mem->state_interface, interface)) {
+ ao2_ref(mem, -1);
+ ret = 1;
+ break;
+ }
ao2_ref(mem, -1);
- ret = 1;
}
ast_mutex_unlock(&q->lock);
if (ret)
@@ -1108,7 +1121,7 @@ static void queue_set_param(struct call_queue *q, const char *param, const char
}
}
-static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str)
+static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str, const char *state_interface)
{
struct member *m, tmpmem;
int penalty = 0;
@@ -1132,10 +1145,10 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, const
/* Create a new one if not found, else update penalty */
if (!m) {
- if ((m = create_queue_member(interface, membername, penalty, paused))) {
+ if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
m->dead = 0;
m->realtime = 1;
- add_to_interfaces(interface);
+ add_to_interfaces(m->state_interface);
ao2_link(q->members, m);
ao2_ref(m, -1);
m = NULL;
@@ -1145,6 +1158,11 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, const
m->dead = 0; /* Do not delete this one. */
if (paused_str)
m->paused = paused;
+ if (strcasecmp(state_interface, m->state_interface)) {
+ remove_from_interfaces(m->state_interface);
+ ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
+ add_to_interfaces(m->state_interface);
+ }
m->penalty = penalty;
ao2_ref(m, -1);
}
@@ -1159,7 +1177,7 @@ static void free_members(struct call_queue *q, int all)
while ((cur = ao2_iterator_next(&mem_iter))) {
if (all || !cur->dynamic) {
ao2_unlink(q->members, cur);
- remove_from_interfaces(cur->interface);
+ remove_from_interfaces(cur->state_interface);
q->membercount--;
}
ao2_ref(cur, -1);
@@ -1278,7 +1296,8 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as
rt_handle_member_record(q, interface,
ast_variable_retrieve(member_config, interface, "membername"),
ast_variable_retrieve(member_config, interface, "penalty"),
- ast_variable_retrieve(member_config, interface, "paused"));
+ ast_variable_retrieve(member_config, interface, "paused"),
+ S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
}
/* Delete all realtime members that have been deleted in DB. */
@@ -1287,7 +1306,7 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as
if (m->dead) {
ao2_unlink(q->members, m);
ast_mutex_unlock(&q->lock);
- remove_from_interfaces(m->interface);
+ remove_from_interfaces(m->state_interface);
ast_mutex_lock(&q->lock);
q->membercount--;
}
@@ -1348,7 +1367,8 @@ static void update_realtime_members(struct call_queue *q)
rt_handle_member_record(q, interface,
S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
ast_variable_retrieve(member_config, interface, "penalty"),
- ast_variable_retrieve(member_config, interface, "paused"));
+ ast_variable_retrieve(member_config, interface, "paused"),
+ S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
}
/* Delete all realtime members that have been deleted in DB. */
@@ -1357,7 +1377,7 @@ static void update_realtime_members(struct call_queue *q)
if (m->dead) {
ao2_unlink(q->members, m);
ast_mutex_unlock(&q->lock);
- remove_from_interfaces(m->interface);
+ remove_from_interfaces(m->state_interface);
ast_mutex_lock(&q->lock);
q->membercount--;
}
@@ -1855,7 +1875,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
ast_cdr_busy(qe->chan->cdr);
tmp->stillgoing = 0;
- update_status(tmp->member->interface, ast_device_state(tmp->member->interface));
+ update_status(tmp->member->interface, ast_device_state(tmp->member->state_interface));
ast_mutex_lock(&qe->parent->lock);
qe->parent->rrpos++;
@@ -3258,7 +3278,7 @@ static struct member *interface_exists(struct call_queue *q, const char *interfa
/* Dump all members in a specific queue to the database
*
- * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
+ * <pm_family>/<queuename> = <interface>;<penalty>;<paused>;<state_interface>[|...]
*
*/
static void dump_queue_members(struct call_queue *pm_queue)
@@ -3281,8 +3301,8 @@ static void dump_queue_members(struct call_queue *pm_queue)
continue;
}
- res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s",
- value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername);
+ res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s",
+ value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface);
ao2_ref(cur_member, -1);
@@ -3332,6 +3352,7 @@ static int remove_from_queue(const char *queuename, const char *interface)
"MemberName: %s\r\n",
q->name, mem->interface, mem->membername);
ao2_unlink(q->members, mem);
+ remove_from_interfaces(mem->state_interface);
ao2_ref(mem, -1);
if (queue_persistent_members)
@@ -3345,16 +3366,13 @@ static int remove_from_queue(const char *queuename, const char *interface)
break;
}
- if (res == RES_OKAY)
- remove_from_interfaces(interface);
-
AST_LIST_UNLOCK(&queues);
return res;
}
-static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump)
+static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface)
{
struct call_queue *q;
struct member *new_member, *old_member;
@@ -3369,8 +3387,8 @@ static int add_to_queue(const char *queuename, const char *interface, const char
ast_mutex_lock(&q->lock);
if ((old_member = interface_exists(q, interface)) == NULL) {
- add_to_interfaces(interface);
- if ((new_member = create_queue_member(interface, membername, penalty, paused))) {
+ if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) {
+ add_to_interfaces(new_member->state_interface);
new_member->dynamic = 1;
ao2_link(q->members, new_member);
q->membercount++;
@@ -3462,6 +3480,7 @@ static void reload_queue_members(void)
char *member;
char *interface;
char *membername = NULL;
+ char *state_interface;
char *penalty_tok;
int penalty = 0;
char *paused_tok;
@@ -3510,6 +3529,7 @@ static void reload_queue_members(void)
penalty_tok = strsep(&member, ";");
paused_tok = strsep(&member, ";");
membername = strsep(&member, ";");
+ state_interface = strsep(&member,";");
if (!penalty_tok) {
ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
@@ -3536,7 +3556,7 @@ static void reload_queue_members(void)
if (option_debug)
ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused);
- if (add_to_queue(queue_name, interface, membername, penalty, paused, 0) == RES_OUTOFMEMORY) {
+ if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) {
ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
break;
}
@@ -3735,11 +3755,12 @@ static int aqm_exec(struct ast_channel *chan, void *data)
AST_APP_ARG(penalty);
AST_APP_ARG(options);
AST_APP_ARG(membername);
+ AST_APP_ARG(state_interface);
);
int penalty = 0;
if (ast_strlen_zero(data)) {
- ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options][|membername]])\n");
+ ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|interface[|penalty[|options[|membername[|state_interface]]]]])\n");
return -1;
}
@@ -3768,7 +3789,7 @@ static int aqm_exec(struct ast_channel *chan, void *data)
priority_jump = 1;
}
- switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members)) {
+ switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) {
case RES_OKAY:
ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
@@ -4293,13 +4314,14 @@ static int reload_queues(void)
int new;
const char *general_val = NULL;
char parse[80];
- char *interface;
+ char *interface, *state_interface;
char *membername = NULL;
int penalty;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(interface);
AST_APP_ARG(penalty);
AST_APP_ARG(membername);
+ AST_APP_ARG(state_interface);
);
if (!(cfg = ast_config_load("queues.conf"))) {
@@ -4377,8 +4399,7 @@ static int reload_queues(void)
interface = args.interface;
if (!ast_strlen_zero(args.penalty)) {
- tmp = args.penalty;
- while (*tmp && *tmp < 33) tmp++;
+ tmp = ast_skip_blanks(args.penalty);
penalty = atoi(tmp);
if (penalty < 0) {
penalty = 0;
@@ -4387,15 +4408,28 @@ static int reload_queues(void)
penalty = 0;
if (!ast_strlen_zero(args.membername)) {
- membername = args.membername;
- while (*membername && *membername < 33) membername++;
+ membername = ast_skip_blanks(args.membername);
+ }
+
+ if (!ast_strlen_zero(args.state_interface)) {
+ state_interface = ast_skip_blanks(args.state_interface);
+ } else {
+ state_interface = interface;
}
/* Find the old position in the list */
ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
- newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0);
+ /* Only attempt removing from interfaces list if the new state_interface is different than the old one */
+ if (cur && strcasecmp(cur->state_interface, state_interface)) {
+ remove_from_interfaces(cur->state_interface);
+ }
+
+ newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface);
+ if (!cur || (cur && strcasecmp(cur->state_interface, state_interface))) {
+ add_to_interfaces(state_interface);
+ }
ao2_link(q->members, newm);
ao2_ref(newm, -1);
newm = NULL;
@@ -4403,8 +4437,6 @@ static int reload_queues(void)
if (cur)
ao2_ref(cur, -1);
else {
- /* Add them to the master int list if necessary */
- add_to_interfaces(interface);
q->membercount++;
}
} else {
@@ -4422,7 +4454,7 @@ static int reload_queues(void)
q->membercount--;
ao2_unlink(q->members, cur);
- remove_from_interfaces(cur->interface);
+ remove_from_interfaces(cur->state_interface);
ao2_ref(cur, -1);
}
@@ -4751,7 +4783,7 @@ static int manager_queues_status(struct mansession *s, const struct message *m)
static int manager_add_queue_member(struct mansession *s, const struct message *m)
{
- const char *queuename, *interface, *penalty_s, *paused_s, *membername;
+ const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface;
int paused, penalty = 0;
queuename = astman_get_header(m, "Queue");
@@ -4759,6 +4791,7 @@ static int manager_add_queue_member(struct mansession *s, const struct message *
penalty_s = astman_get_header(m, "Penalty");
paused_s = astman_get_header(m, "Paused");
membername = astman_get_header(m, "MemberName");
+ state_interface = astman_get_header(m, "StateInterface");
if (ast_strlen_zero(queuename)) {
astman_send_error(s, m, "'Queue' not specified.");
@@ -4780,7 +4813,7 @@ static int manager_add_queue_member(struct mansession *s, const struct message *
else
paused = abs(ast_true(paused_s));
- switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members)) {
+ switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) {
case RES_OKAY:
ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", "");
astman_send_ack(s, m, "Added interface to queue");
@@ -4858,7 +4891,7 @@ static int manager_pause_queue_member(struct mansession *s, const struct message
static int handle_queue_add_member(int fd, int argc, char *argv[])
{
- char *queuename, *interface, *membername = NULL;
+ char *queuename, *interface, *membername = NULL, *state_interface = NULL;
int penalty;
if ((argc != 6) && (argc != 8) && (argc != 10)) {
@@ -4891,7 +4924,11 @@ static int handle_queue_add_member(int fd, int argc, char *argv[])
membername = argv[9];
}
- switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members)) {
+ if (argc >= 12) {
+ state_interface = argv[11];
+ }
+
+ switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) {
case RES_OKAY:
ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
@@ -4936,6 +4973,8 @@ static char *complete_queue_add_member(const char *line, const char *word, int p
return state == 0 ? ast_strdup("as") : NULL;
case 9: /* Don't attempt to complete name of member (infinite possibilities) */
return NULL;
+ case 10:
+ return state == 0 ? ast_strdup("state_interface") : NULL;
default:
return NULL;
}
@@ -5019,7 +5058,7 @@ static char queue_show_usage[] =
" Provides summary information on a specified queue.\n";
static char qam_cmd_usage[] =
-"Usage: queue add member <channel> to <queue> [penalty <penalty>]\n";
+"Usage: queue add member <channel> to <queue> [penalty <penalty> [as <membername> [state_interface <state_interface>]]]\n";
static char qrm_cmd_usage[] =
"Usage: queue remove member <channel> from <queue>\n";
diff --git a/configs/queues.conf.sample b/configs/queues.conf.sample
index 64f698527..a4f714df4 100644
--- a/configs/queues.conf.sample
+++ b/configs/queues.conf.sample
@@ -291,7 +291,10 @@ monitor-type = MixMonitor
; entries with higher penalties are considered last. An optional member
; name may also be specified after a second comma, which is used in log
; messages as a "friendly name". Multiple interfaces may share a single
-; member name.
+; member name. An optional state interface may be specified after a third
+; comma. This interface will be the one for which app_queue receives device
+; state notifications, even though the first interface specified is the one
+; that is actually called.
;
; It is important to ensure that channel drivers used for members are loaded
; before app_queue.so itself or they may be marked invalid until reload. This
@@ -305,6 +308,7 @@ monitor-type = MixMonitor
;member => Zap/3,10,Bob Johnson
;member => Agent/1001
;member => Agent/1002
+;member => Local/1000@default,0,John Smith,SIP/1000
;
; Note that using agent groups is probably not what you want. Strategies do