[asterisk-commits] irroot: branch irroot/patches r344958 - /team/irroot/patches/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Sat Nov 12 08:28:33 CST 2011
Author: irroot
Date: Sat Nov 12 08:28:29 2011
New Revision: 344958
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=344958
Log:
Distrotech patch for 10.0.0-rc1 [342951]
Added:
team/irroot/patches/distrotech-10.0.patch (with props)
Added: team/irroot/patches/distrotech-10.0.patch
URL: http://svnview.digium.com/svn/asterisk/team/irroot/patches/distrotech-10.0.patch?view=auto&rev=344958
==============================================================================
--- team/irroot/patches/distrotech-10.0.patch (added)
+++ team/irroot/patches/distrotech-10.0.patch Sat Nov 12 08:28:29 2011
@@ -1,0 +1,9132 @@
+Index: channels/chan_sip.c
+===================================================================
+--- channels/chan_sip.c (.../digium/10) (revision 900)
++++ channels/chan_sip.c (.../distrotech/10/10.1.0) (revision 900)
+@@ -5601,17 +5601,23 @@
+
+ if (p->rtp && !p->srtp && setup_srtp(&p->srtp) < 0) {
+ ast_log(LOG_WARNING, "SRTP audio setup failed\n");
+- return -1;
++ if (!ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++ return -1;
++ }
+ }
+
+ if (p->vrtp && !p->vsrtp && setup_srtp(&p->vsrtp) < 0) {
+ ast_log(LOG_WARNING, "SRTP video setup failed\n");
+- return -1;
++ if (!ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++ return -1;
++ }
+ }
+
+ if (p->trtp && !p->tsrtp && setup_srtp(&p->tsrtp) < 0) {
+ ast_log(LOG_WARNING, "SRTP text setup failed\n");
+- return -1;
++ if (!ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++ return -1;
++ }
+ }
+ }
+
+@@ -9205,32 +9211,48 @@
+
+ if (secure_audio && !(p->srtp && (ast_test_flag(p->srtp, SRTP_CRYPTO_OFFER_OK)))) {
+ ast_log(LOG_WARNING, "Can't provide secure audio requested in SDP offer\n");
+- res = -4;
+- goto process_sdp_cleanup;
++ if (!ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++ res = -4;
++ goto process_sdp_cleanup;
++ }
+ }
+
+ if (!secure_audio && p->srtp) {
+ ast_log(LOG_WARNING, "We are requesting SRTP, but they responded without it!\n");
+- res = -4;
+- goto process_sdp_cleanup;
++ if (ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++ sip_srtp_destroy(p->srtp);
++ p->srtp = NULL;
++ } else {
++ res = -4;
++ goto process_sdp_cleanup;
++ }
+ }
+
+ if (secure_video && !(p->vsrtp && (ast_test_flag(p->vsrtp, SRTP_CRYPTO_OFFER_OK)))) {
+ ast_log(LOG_WARNING, "Can't provide secure video requested in SDP offer\n");
+- res = -4;
+- goto process_sdp_cleanup;
++ if (!ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++ res = -4;
++ goto process_sdp_cleanup;
++ }
+ }
+
+ if (!p->novideo && !secure_video && p->vsrtp) {
+ ast_log(LOG_WARNING, "We are requesting SRTP, but they responded without it!\n");
+- res = -4;
+- goto process_sdp_cleanup;
++ if (ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++ sip_srtp_destroy(p->vsrtp);
++ p->vsrtp = NULL;
++ } else {
++ res = -4;
++ goto process_sdp_cleanup;
++ }
+ }
+
+ if (!(secure_audio || secure_video) && ast_test_flag(&p->flags[1], SIP_PAGE2_USE_SRTP)) {
+ ast_log(LOG_WARNING, "Matched device setup to use SRTP, but request was not!\n");
+- res = -4;
+- goto process_sdp_cleanup;
++ if (!ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
++ res = -4;
++ goto process_sdp_cleanup;
++ }
+ }
+
+ if (udptlportno == -1) {
+@@ -23194,7 +23216,8 @@
+ transmit_response_with_t38_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (req->ignore ? XMIT_UNRELIABLE : XMIT_CRITICAL)));
+ } else if ((p->t38.state == T38_DISABLED) || (p->t38.state == T38_REJECTED)) {
+ /* If this is not a re-invite or something to ignore - it's critical */
+- if (p->srtp && !ast_test_flag(p->srtp, SRTP_CRYPTO_OFFER_OK)) {
++ if (p->srtp && !ast_test_flag(p->srtp, SRTP_CRYPTO_OFFER_OK) &&
++ !ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TRY)) {
+ ast_log(LOG_WARNING, "Target does not support required crypto\n");
+ transmit_response_reliable(p, "488 Not Acceptable Here (crypto)", req);
+ } else {
+@@ -27422,6 +27445,11 @@
+ int duplicate = 0;
+ /* remove leading/trailing whitespace from mailbox string */
+ mbox = ast_strip(mbox);
++ if (strstr("@",context) == NULL) {
++ strncat(context,"@",sizeof(context)-2);
++ strncat(context,peer->context,sizeof(context)-strlen(peer->context)-1);
++ }
++
+ strsep(&context, "@");
+
+ if (ast_strlen_zero(mbox)) {
+@@ -27898,7 +27926,13 @@
+ } else if (!strcasecmp(v->name, "use_q850_reason")) {
+ ast_set2_flag(&peer->flags[1], ast_true(v->value), SIP_PAGE2_Q850_REASON);
+ } else if (!strcasecmp(v->name, "encryption")) {
+- ast_set2_flag(&peer->flags[1], ast_true(v->value), SIP_PAGE2_USE_SRTP);
++ if (!strcasecmp(v->value, "try")) {
++ ast_set_flag(&peer->flags[1], SIP_PAGE2_USE_SRTP);
++ ast_set_flag(&peer->flags[2], SIP_PAGE3_SRTP_TRY);
++ } else {
++ ast_set2_flag(&peer->flags[1], ast_true(v->value), SIP_PAGE2_USE_SRTP);
++ ast_clear_flag(&peer->flags[2], SIP_PAGE3_SRTP_TRY);
++ }
+ } else if (!strcasecmp(v->name, "encryption_taglen")) {
+ ast_set2_flag(&peer->flags[2], !strcasecmp(v->value, "32"), SIP_PAGE3_SRTP_TAG_32);
+ } else if (!strcasecmp(v->name, "snom_aoc_enabled")) {
+Index: channels/chan_misdn.c
+===================================================================
+--- channels/chan_misdn.c (.../digium/10) (revision 900)
++++ channels/chan_misdn.c (.../distrotech/10/10.1.0) (revision 900)
+@@ -7891,6 +7891,7 @@
+ int port_up;
+ int check;
+ int maxbchans;
++ int wraped = 0;
+
+ if (!rr->port) {
+ rr->port = misdn_cfg_get_next_port_spin(0);
+@@ -7926,6 +7927,11 @@
+ maxbchans = misdn_lib_get_maxchans(rr->port);
+
+ for (;rr->channel <= maxbchans;rr->channel++) {
++ /* ive come full circle and can stop now */
++ if (wraped && (rr->port == port_start) && (rr->channel == bchan_start)) {
++ break;
++ }
++
+ chan_misdn_log(4, rr->port, "Checking channel %d\n", rr->channel);
+
+ if ((newbc = misdn_lib_get_free_bc(rr->port, rr->channel, 0, 0))) {
+@@ -7940,9 +7946,9 @@
+ }
+
+ }
++ wraped = 1;
+ } while (!newbc && (rr->port > 0) &&
+ ((rr->port != port_start) || ((rr->port == port_start) && (rr->channel < bchan_start))));
+-
+ } else {
+ for (port = misdn_cfg_get_next_port(0); port > 0;
+ port = misdn_cfg_get_next_port(port)) {
+Index: channels/sip/include/sip.h
+===================================================================
+--- channels/sip/include/sip.h (.../digium/10) (revision 900)
++++ channels/sip/include/sip.h (.../distrotech/10/10.1.0) (revision 900)
+@@ -354,9 +354,10 @@
+
+ #define SIP_PAGE3_SNOM_AOC (1 << 0) /*!< DPG: Allow snom aoc messages */
+ #define SIP_PAGE3_SRTP_TAG_32 (1 << 1) /*!< DP: Use a 32bit auth tag in INVITE not 80bit */
++#define SIP_PAGE3_SRTP_TRY (1 << 2) /*!< DP: Attempt SRTP / do not enforce it */
+
+ #define SIP_PAGE3_FLAGS_TO_COPY \
+- (SIP_PAGE3_SNOM_AOC | SIP_PAGE3_SRTP_TAG_32)
++ (SIP_PAGE3_SNOM_AOC | SIP_PAGE3_SRTP_TAG_32 | SIP_PAGE3_SRTP_TRY)
+
+ #define CHECK_AUTH_BUF_INITLEN 256
+
+Index: channels/chan_local.c
+===================================================================
+--- channels/chan_local.c (.../digium/10) (revision 900)
++++ channels/chan_local.c (.../distrotech/10/10.1.0) (revision 900)
+@@ -649,9 +649,10 @@
+ static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
+ {
+ struct local_pvt *p = ast->tech_pvt;
++ struct ast_channel *bridge;
+ int res = 0;
+ struct ast_frame f = { AST_FRAME_CONTROL, };
+- int isoutbound;
++ int isoutbound = IS_OUTBOUND(ast, p);
+
+ if (!p)
+ return -1;
+@@ -674,7 +675,6 @@
+ * happens to be in this control frame. The same applies for redirecting information, which
+ * is why it is handled here as well.*/
+ ao2_lock(p);
+- isoutbound = IS_OUTBOUND(ast, p);
+ if (isoutbound) {
+ this_channel = p->chan;
+ the_other_channel = p->owner;
+@@ -697,10 +697,33 @@
+ res = local_queue_frame(p, isoutbound, &f, ast, 1);
+ }
+ ao2_unlock(p);
++ } else if (!isoutbound && (condition == AST_CONTROL_SRCUPDATE)) {
++ bridge = ast_bridged_channel(ast);
++ ao2_lock(p);
++ /* fixup audio formats nativeformat might have changed we must adjust.
++ * ast is p->owner and is locked here*/
++ if (p->chan && bridge && (bridge != p->chan) &&
++ !ast_format_cap_identical(bridge->nativeformats, ast->nativeformats)) {
++ if (!ast_channel_trylock(p->chan)) {
++ ast_format_cap_copy(ast->nativeformats, bridge->nativeformats);
++ ast_set_read_format(ast, &ast->readformat);
++ ast_set_write_format(ast, &ast->writeformat);
++ ast_format_cap_copy(p->chan->nativeformats, bridge->nativeformats);
++ ast_set_read_format(p->chan, &p->chan->readformat);
++ ast_set_write_format(p->chan, &p->chan->writeformat);
++ ast_channel_unlock(p->chan);
++ } else {
++ ast_verb(3, "Tried to get lock on %s to set audio format but failed\n", p->chan->name);
++ }
++ }
++ f.subclass.integer = condition;
++ f.data.ptr = (void*)data;
++ f.datalen = datalen;
++ res = local_queue_frame(p, isoutbound, &f, ast, 1);
++ ao2_unlock(p);
+ } else {
+ /* Queue up a frame representing the indication as a control frame */
+ ao2_lock(p);
+- isoutbound = IS_OUTBOUND(ast, p);
+ f.subclass.integer = condition;
+ f.data.ptr = (void*)data;
+ f.datalen = datalen;
+Index: channels/misdn/Makefile
+===================================================================
+--- channels/misdn/Makefile (.../digium/10) (revision 900)
++++ channels/misdn/Makefile (.../distrotech/10/10.1.0) (revision 900)
+@@ -11,7 +11,7 @@
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+ portinfo: portinfo.o
+- $(CC) -o $@ $^ -lisdnnet -lmISDN -lpthread
++ $(CC) -o $@ $^ -lisdnnet-1 -lmISDN -lpthread
+
+ clean:
+ rm -rf *.a *.o *.so portinfo *.i
+Index: configure.ac
+===================================================================
+--- configure.ac (.../digium/10) (revision 900)
++++ configure.ac (.../distrotech/10/10.1.0) (revision 900)
+@@ -389,7 +389,8 @@
+ AST_EXT_LIB_SETUP([IMAP_TK], [UW IMAP Toolkit], [imap])
+ AST_EXT_LIB_SETUP([INOTIFY], [inotify support], [inotify])
+ AST_EXT_LIB_SETUP([IODBC], [iODBC], [iodbc])
+-AST_EXT_LIB_SETUP([ISDNNET], [ISDN4Linux], [isdnnet])
++AST_EXT_LIB_SETUP([ISDNNET], [ISDN4Linux], [isdnnet-1])
++AST_EXT_LIB_SETUP([SUPPSERV], [mISDN Supplemental Services], [suppserv-1])
+ AST_EXT_LIB_SETUP([JACK], [Jack Audio Connection Kit], [jack])
+ AST_EXT_LIB_SETUP([KQUEUE], [kqueue support], [kqueue])
+ AST_EXT_LIB_SETUP([LDAP], [OpenLDAP], [ldap])
+@@ -453,7 +454,6 @@
+ AST_EXT_LIB_SETUP([SQLITE3], [SQLite], [sqlite3])
+ AST_EXT_LIB_SETUP([SRTP], [Secure RTP], [srtp])
+ AST_EXT_LIB_SETUP([OPENSSL], [OpenSSL Secure Sockets Layer], [ssl])
+-AST_EXT_LIB_SETUP([SUPPSERV], [mISDN Supplemental Services], [suppserv])
+ AST_EXT_LIB_SETUP([FREETDS], [FreeTDS], [tds])
+ AST_EXT_LIB_SETUP([TERMCAP], [Termcap], [termcap])
+ AST_EXT_LIB_SETUP([TIMERFD], [timerfd], [timerfd])
+@@ -1737,11 +1737,11 @@
+ AST_EXT_LIB_CHECK([MISDN], [mISDN], [mISDN_open], [mISDNuser/mISDNlib.h])
+
+ if test "${PBX_MISDN}" = 1; then
+- AST_EXT_LIB_CHECK([ISDNNET], [isdnnet], [init_manager], [mISDNuser/isdn_net.h], [-lmISDN -lpthread])
+- AST_EXT_LIB_CHECK([SUPPSERV], [suppserv], [encodeFac], [mISDNuser/suppserv.h])
++ AST_EXT_LIB_CHECK([ISDNNET], [isdnnet-1], [init_manager], [mISDNuser/isdn_net.h], [-lmISDN -lpthread])
++ AST_EXT_LIB_CHECK([SUPPSERV], [suppserv-1], [encodeFac], [mISDNuser/suppserv.h])
+ AST_C_DEFINE_CHECK([MISDN_FAC_RESULT], [Fac_RESULT], [mISDNuser/suppserv.h])
+ AST_C_DEFINE_CHECK([MISDN_FAC_ERROR], [Fac_ERROR], [mISDNuser/suppserv.h])
+- AC_CHECK_HEADER([linux/mISDNdsp.h], [AC_DEFINE_UNQUOTED([MISDN_1_2], 1, [Build chan_misdn for mISDN 1.2 or later.])])
++ AC_CHECK_HEADER([mISDN/mISDNdsp.h], [AC_DEFINE_UNQUOTED([MISDN_1_2], 1, [Build chan_misdn for mISDN 1.2 or later.])])
+ AC_CHECK_MEMBER([Q931_info_t.redirect_dn], [], [PBX_MISDN=0], [#include <mISDNuser/mISDNlib.h>])
+ fi
+
+Index: apps/app_directed_pickup.c
+===================================================================
+--- apps/app_directed_pickup.c (.../digium/10) (revision 900)
++++ apps/app_directed_pickup.c (.../distrotech/10/10.1.0) (revision 900)
+@@ -73,7 +73,10 @@
+ tries to find a channel which has defined a <variable>PICKUPMARK</variable>
+ channel variable with the same value as <replaceable>extension</replaceable>
+ (in this example, <literal>10</literal>). When no parameter is specified, the application
+- will pickup a channel matching the pickup group of the active channel.</para>
++ will pickup a channel matching the pickup group of the active channel.
++ If the channel variable <variable>PICKUP_BRIDGE_MACRO</variable> is set this macro will run
++ on the picked up channel using the channel variable <variable>PICKUP_BRIDGE_MACRO_ARGS</variable>
++ as arguments.</para>
+ </description>
+ </application>
+ <application name="PickupChan" language="en_US">
+@@ -94,7 +97,10 @@
+ </parameter>
+ </syntax>
+ <description>
+- <para>This will pickup a specified <replaceable>channel</replaceable> if ringing.</para>
++ <para>This will pickup a specified <replaceable>channel</replaceable> if ringing.
++ If the channel variable <variable>PICKUP_BRIDGE_MACRO</variable> is set this macro will run
++ on the picked up channel using the channel variable <variable>PICKUP_BRIDGE_MACRO_ARGS</variable>
++ as arguments.</para>
+ </description>
+ </application>
+ ***/
+Index: apps/app_queue.c
+===================================================================
+--- apps/app_queue.c (.../digium/10) (revision 900)
++++ apps/app_queue.c (.../distrotech/10/10.1.0) (revision 900)
+@@ -25,6 +25,18 @@
+ * \arg Config in \ref Config_qu queues.conf
+ *
+ * \par Development notes
++ * \note 2011-11-01: Made application more thread safe
++ * Distrotech PTY (LTD) (www.distrotech.co.za)
++ * Gregory Nietsky (irroot) <gregory at distrotech.co.za>
++ *
++ * Split away from locking queues/queue to having locks per
++ * Queue/Member/Device.
++ * Added device state struct to mange device states shared
++ * for multiple members sharing same device.
++ *
++ * Made all functions work with realtime/dynamic/static members.
++ * Added missing CLI/AMI functions for handling callinuse.
++ *
+ * \note 2004-11-25: Persistent Dynamic Members added by:
+ * NetNation Communications (www.netnation.com)
+ * Kevin Lindsay <kevinl at netnation.com>
+@@ -99,22 +111,31 @@
+ #include "asterisk/callerid.h"
+ #include "asterisk/cel.h"
+ #include "asterisk/data.h"
++#include "asterisk/time.h"
+
+-/* Define, to debug reference counts on queues, without debugging reference counts on queue members */
+-/* #define REF_DEBUG_ONLY_QUEUES */
+-
+ /*!
+ * \par Please read before modifying this file.
+- * There are three locks which are regularly used
+- * throughout this file, the queue list lock, the lock
+- * for each individual queue, and the interface list lock.
++ * There are locks which are regularly used
++ * throughout this file, the lock
++ * for each individual queue, the individual member lock ,
++ * and the device state lock.
++ * there are container locks for the queues list, the member
++ * list on each queue and the devices container.
+ * Please be extra careful to always lock in the following order
+- * 1) queue list lock
+- * 2) individual queue lock
+- * 3) interface list lock
++ *
++ * 1) queues container lock (ao2 functions that lock the container)
++ * 2) queue lock
++ * 3) queue member lock
++ * 4) member lock
++ * 5) devices container lock
++ * 6) member device lock
+ * This order has sort of "evolved" over the lifetime of this
+ * application, but it is now in place this way, so please adhere
+ * to this order!
++ *
++ * the only elements that do not require a read lock (ie will not change)
++ * the queue name and members container, the member interface and
++ * device state_interface as they are never altered after been linked.
+ */
+
+ /*** DOCUMENTATION
+@@ -264,9 +285,10 @@
+ <parameter name="queuename" required="true" />
+ <parameter name="interface" />
+ <parameter name="penalty" />
+- <parameter name="options" />
++ <parameter name="paused" />
+ <parameter name="membername" />
+ <parameter name="stateinterface" />
++ <parameter name="callinuse" />
+ </syntax>
+ <description>
+ <para>Dynamically adds interface to an existing queue. If the interface is
+@@ -530,8 +552,8 @@
+ <enum name="paused">
+ <para>Gets or sets queue member paused status.</para>
+ </enum>
+- <enum name="ignorebusy">
+- <para>Gets or sets queue member ignorebusy.</para>
++ <enum name="callinuse">
++ <para>Gets or sets queue member callinuse.</para>
+ </enum>
+ </enumlist>
+ </parameter>
+@@ -846,6 +868,19 @@
+ <description>
+ </description>
+ </manager>
++ <manager name="QueueCallInuse" language="en_US">
++ <synopsis>
++ Set interface to allow multiple calls
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Interface" required="true" />
++ <parameter name="CallInuse" required="true" />
++ <parameter name="Queue" required="true" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
+ ***/
+
+ enum {
+@@ -870,8 +905,15 @@
+ QUEUE_RELOAD_MEMBER = (1 << 1),
+ QUEUE_RELOAD_RULES = (1 << 2),
+ QUEUE_RESET_STATS = (1 << 3),
++ QUEUE_RELOAD_REALTIME = (1 << 4),
+ };
+
++enum member_type {
++ QUEUE_ADD_MEMBER_STATIC = (1 << 0),
++ QUEUE_ADD_MEMBER_REALTIME = (1 << 1),
++ QUEUE_ADD_MEMBER_DYNAMIC = (1 << 2),
++};
++
+ static const struct strategy {
+ int strategy;
+ const char *name;
+@@ -912,7 +954,7 @@
+ #define RES_OUTOFMEMORY (-2) /*!< Out of memory */
+ #define RES_NOSUCHQUEUE (-3) /*!< No such queue */
+ #define RES_NOT_DYNAMIC (-4) /*!< Member is not dynamic */
+-
++#define RES_ERROR (-5) /*!< Member is mis configured */
+ static char *app = "Queue";
+
+ static char *app_aqm = "AddQueueMember" ;
+@@ -955,7 +997,7 @@
+ static int negative_penalty_invalid = 0;
+
+ /*! \brief queues.conf [general] option */
+-static int check_state_unknown = 0;
++static int log_membername_as_agent = 0;
+
+ enum queue_result {
+ QUEUE_UNKNOWN = 0,
+@@ -991,48 +1033,32 @@
+ * use it not only for keeping track of what is in use but
+ * also for keeping track of who we're dialing.
+ *
+- * There are two "links" defined in this structure, q_next and call_next.
+- * q_next links ALL defined callattempt structures into a linked list. call_next is
+- * a link which allows for a subset of the callattempts to be traversed. This subset
+- * is used in wait_for_answer so that irrelevant callattempts are not traversed. This
+- * also is helpful so that queue logs are always accurate in the case where a call to
+- * a member times out, especially if using the ringall strategy.
+ */
+
+ struct callattempt {
+- struct callattempt *q_next;
+- struct callattempt *call_next;
+- struct ast_channel *chan;
+- char interface[256];
+- int stillgoing;
+- int metric;
+- time_t lastcall;
+- struct call_queue *lastqueue;
+- struct member *member;
+- /*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
+- struct ast_party_connected_line connected;
+- /*! TRUE if an AST_CONTROL_CONNECTED_LINE update was saved to the connected element. */
+- unsigned int pending_connected_update:1;
+- /*! TRUE if caller id is not available for connected line */
+- unsigned int dial_callerid_absent:1;
++ struct ast_channel *chan; /*! Channel called */
++ int stillgoing; /*! This attempt is valid and active */
++ int metric; /*! Metric calculated according to strategy */
++ struct member *member; /*! Member assosiated with this attempt */
++ struct ast_party_connected_line connected; /*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
++ unsigned int reserved:1; /*! Is this attempt been attempted*/
++ unsigned int active:1; /*! Is this attempt active in a call*/
++ unsigned int pending_connected_update:1; /*! TRUE if caller id is not available for connected line*/
++ unsigned int dial_callerid_absent:1; /*! TRUE if caller id is not available for connected line */
+ struct ast_aoc_decoded *aoc_s_rate_list;
+ };
+
+-
+ struct queue_ent {
+ struct call_queue *parent; /*!< What queue is our parent */
+- char moh[80]; /*!< Name of musiconhold to be used */
+- char announce[PATH_MAX]; /*!< Announcement to play for member when call is answered */
+- char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
+ char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
+ int valid_digits; /*!< Digits entered correspond to valid extension. Exited */
+ int pos; /*!< Where we are in the queue */
+ int prio; /*!< Our priority */
+ int last_pos_said; /*!< Last position we told the user */
+ int ring_when_ringing; /*!< Should we only use ring indication when a channel is ringing? */
+- time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
++ struct timeval last_pannounce_time; /*!< The last time we played a periodic announcement */
+ int last_periodic_announce_sound; /*!< The last periodic announcement we made */
+- time_t last_pos; /*!< Last time we told the user their position */
++ struct timeval last_pos; /*!< Last time we told the user their position */
+ int opos; /*!< Where we started in the queue */
+ int handled; /*!< Whether our call was handled */
+ int pending; /*!< Non-zero if we are attempting to call a member */
+@@ -1040,33 +1066,40 @@
+ int min_penalty; /*!< Limit the members that can take this call to this penalty or higher */
+ int linpos; /*!< If using linear strategy, what position are we at? */
+ int linwrapped; /*!< Is the linpos wrapped? */
+- time_t start; /*!< When we started holding */
+- time_t expire; /*!< When this entry should expire (time out of queue) */
++ struct timeval start; /*!< When we started holding */
++ struct timeval expire; /*!< When this entry should expire (time out of queue) */
+ int cancel_answered_elsewhere; /*!< Whether we should force the CAE flag on this call (C) option*/
++ struct ao2_container *attempts; /*!< Container holding all call attempts*/
+ struct ast_channel *chan; /*!< Our channel */
+- AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules; /*!< Local copy of the queue's penalty rules */
+- struct penalty_rule *pr; /*!< Pointer to the next penalty rule to implement */
+- struct queue_ent *next; /*!< The next queue entry */
++ struct rule_list *rules; /*!< Pointer holding the ref for the queue penalty rules */
++ struct penalty_rule *pr; /*!< Active penalty rule */
++ AST_LIST_ENTRY(queue_ent) next; /*!< The next queue entry */
+ };
+
++/*! \brief keep track of device state changes */
++struct mem_state {
++ char state_interface[80]; /*!< Technology/Location from which to read devicestate changes */
++ int reserved; /*!< This interface is reserved for pending call */
++ int active; /*!< This interface is active on a call */
++ int status; /*!< Status of queue member */
++};
++
+ struct member {
+- char interface[80]; /*!< Technology/Location to dial to reach this member*/
+- char state_exten[AST_MAX_EXTENSION]; /*!< Extension to get state from (if using hint) */
+- char state_context[AST_MAX_CONTEXT]; /*!< Context to use when getting state (if using hint) */
+- char state_interface[80]; /*!< Technology/Location from which to read devicestate 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 */
+- int dynamic; /*!< Are we dynamically added? */
+- int realtime; /*!< Is this member realtime? */
+- int status; /*!< Status of queue member */
+- int paused; /*!< Are we paused (not accepting calls)? */
+- time_t lastcall; /*!< When last successful call was hungup */
+- struct call_queue *lastqueue; /*!< Last queue we received a call */
+- unsigned int dead:1; /*!< Used to detect members deleted in realtime */
+- unsigned int delme:1; /*!< Flag to delete entry on reload */
+- char rt_uniqueid[80]; /*!< Unique id of realtime member entry */
+- unsigned int ignorebusy:1; /*!< Flag to ignore member if the status is not available */
++ AST_DECLARE_STRING_FIELDS(
++ AST_STRING_FIELD(interface); /*!< Technology/Location to dial to reach this member*/
++ AST_STRING_FIELD(membername); /*!< Member name to use in queue logs */
++ AST_STRING_FIELD(rt_uniqueid); /*!< Unique id of realtime member entry */
++ );
++ int penalty; /*!< Are we a last resort? */
++ int calls; /*!< Number of calls serviced by this member */
++ struct timeval lastcall; /*!< When last successful call was hungup */
++ int lastwrapup; /*!< Last wrapuptime */
++ unsigned int dynamic:1; /*!< Is this member dynamic? */
++ unsigned int realtime:1; /*!< Is this member realtime? */
++ unsigned int paused:1; /*!< Are we paused (not accepting calls)? */
++ unsigned int dead:1; /*!< Used to detect members deleted in realtime */
++ unsigned int callinuse:1; /*!< Are we dynamically added? */
++ struct mem_state *device; /*!< Device information */
+ };
+
+ enum empty_conditions {
+@@ -1149,7 +1182,6 @@
+ unsigned int setqueuevar:1;
+ unsigned int setqueueentryvar:1;
+ unsigned int reportholdtime:1;
+- unsigned int wrapped:1;
+ unsigned int timeoutrestart:1;
+ unsigned int announceholdtime:2;
+ unsigned int announceposition:3;
+@@ -1158,6 +1190,8 @@
+ unsigned int realtime:1;
+ unsigned int found:1;
+ unsigned int relativeperiodicannounce:1;
++ unsigned int autopausebusy:1;
++ unsigned int autopauseunavail:1;
+ enum empty_conditions joinempty;
+ enum empty_conditions leavewhenempty;
+ int announcepositionlimit; /*!< How many positions we announce? */
+@@ -1167,52 +1201,57 @@
+ int numperiodicannounce; /*!< The number of periodic announcements configured */
+ int randomperiodicannounce; /*!< Are periodic announcments randomly chosen */
+ int roundingseconds; /*!< How many seconds do we round to? */
+- int holdtime; /*!< Current avg holdtime, based on an exponential average */
+- int talktime; /*!< Current avg talktime, based on the same exponential average */
+- int callscompleted; /*!< Number of queue calls completed */
+- int callsabandoned; /*!< Number of queue calls abandoned */
+ int servicelevel; /*!< seconds setting for servicelevel*/
+- int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
+ char monfmt[8]; /*!< Format to use when recording calls */
+ int montype; /*!< Monitor type Monitor vs. MixMonitor */
+- int count; /*!< How many entries */
+ int maxlen; /*!< Max number of entries */
+ int wrapuptime; /*!< Wrapup Time */
+ int penaltymemberslimit; /*!< Disregard penalty when queue has fewer than this many members */
+-
+ int retry; /*!< Retry calling everyone after this amount of time */
+ int timeout; /*!< How long to wait for an answer */
+ int weight; /*!< Respective weight */
+ int autopause; /*!< Auto pause queue members if they fail to answer */
+ int autopausedelay; /*!< Delay auto pause for autopausedelay seconds since last call */
+ int timeoutpriority; /*!< Do we allow a fraction of the timeout to occur for a ring? */
+-
+ /* Queue strategy things */
+- int rrpos; /*!< Round Robin - position */
+ int memberdelay; /*!< Seconds to delay connecting member to caller */
+ int autofill; /*!< Ignore the head call status and ring an available agent */
+-
+- struct ao2_container *members; /*!< Head of the list of members */
+- struct queue_ent *head; /*!< Head of the list of callers */
+- AST_LIST_ENTRY(call_queue) list; /*!< Next call queue */
+- AST_LIST_HEAD_NOLOCK(, penalty_rule) rules; /*!< The list of penalty rules to invoke */
++ struct timeval reload; /*!< Time the queue will be reloaded from RT */
++ struct queue_data *data; /*!< Queue statistics */
+ };
+
++struct queue_data {
++ int qhash; /*!< Hash for queue */
++ unsigned int wrapped:1;
++ int count; /*!< How many entries */
++ int holdtime; /*!< Current avg holdtime, based on an exponential average */
++ int talktime; /*!< Current avg talktime, based on the same exponential average */
++ int callscompleted; /*!< Number of queue calls completed */
++ int callsabandoned; /*!< Number of queue calls abandoned */
++ int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
++ int rrpos; /*!< Round Robin - position */
++ AST_LIST_HEAD(, queue_ent) *head; /*!< Head of the list of callers */
++ struct ao2_container *members; /*!< Head of the list of members */
++};
++
+ struct rule_list {
+ char name[80];
+- AST_LIST_HEAD_NOLOCK(,penalty_rule) rules;
+- AST_LIST_ENTRY(rule_list) list;
++ struct ao2_container *rules;
+ };
+
+-static AST_LIST_HEAD_STATIC(rule_lists, rule_list);
+-
+ static struct ao2_container *queues;
++static struct ao2_container *devices;
++static struct ao2_container *rules;
++static struct ao2_container *qdata;
+
+-static void update_realtime_members(struct call_queue *q);
++static int do_set_member_penalty_paused(struct call_queue *q, struct member *mem, int pause, int value, const char *reason);
++static void pm_load_member_config(struct call_queue *q);
++static char *queue_refshow(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+ static struct member *interface_exists(struct call_queue *q, const char *interface);
+ static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
+
+ static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
++
+ /*! \brief sets the QUEUESTATUS channel variable */
+ static void set_queue_result(struct ast_channel *chan, enum queue_result res)
+ {
+@@ -1226,6 +1265,7 @@
+ }
+ }
+
++/*! \brief return strategy name from strategy*/
+ static const char *int2strat(int strategy)
+ {
+ int x;
+@@ -1238,6 +1278,7 @@
+ return "<unknown>";
+ }
+
++/*! brief return strategy from strategy name*/
+ static int strat2int(const char *strategy)
+ {
+ int x;
+@@ -1250,6 +1291,7 @@
+ return -1;
+ }
+
++/*! brief return a autopause setting from name*/
+ static int autopause2int(const char *autopause)
+ {
+ int x;
+@@ -1270,92 +1312,125 @@
+ return QUEUE_AUTOPAUSE_OFF;
+ }
+
++/*!
++ * \brief ao2 callback to calculate hash of a queue by name
++ */
+ static int queue_hash_cb(const void *obj, const int flags)
+ {
+ const struct call_queue *q = obj;
++ const char *name = q->name;
+
+- return ast_str_case_hash(q->name);
++ return ast_str_case_hash(name);
+ }
+
++
++/*!
++ * \brief ao2 callback to find queue by name
++ * \note this is the default function used by ao2_find
++ */
+ static int queue_cmp_cb(void *obj, void *arg, int flags)
+ {
+- struct call_queue *q = obj, *q2 = arg;
+- return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
++ const struct call_queue *q = obj, *q2 = arg;
++ const char *name = (flags & OBJ_POINTER) ? q2->name : arg;
++
++ return !strcasecmp(q->name, name) ? CMP_MATCH | CMP_STOP : 0;
+ }
+
+-#ifdef REF_DEBUG_ONLY_QUEUES
+-#define queue_ref(a) __ao2_ref_debug(a,1,"",__FILE__,__LINE__,__PRETTY_FUNCTION__)
+-#define queue_unref(a) __ao2_ref_debug(a,-1,"",__FILE__,__LINE__,__PRETTY_FUNCTION__)
+-#define queue_t_ref(a,b) __ao2_ref_debug(a,1,b,__FILE__,__LINE__,__PRETTY_FUNCTION__)
+-#define queue_t_unref(a,b) __ao2_ref_debug(a,-1,b,__FILE__,__LINE__,__PRETTY_FUNCTION__)
+-#define queues_t_link(c,q,tag) __ao2_link_debug(c,q,tag,__FILE__,__LINE__,__PRETTY_FUNCTION__)
+-#define queues_t_unlink(c,q,tag) __ao2_unlink_debug(c,q,tag,__FILE__,__LINE__,__PRETTY_FUNCTION__)
+-#else
+-#define queue_t_ref(a,b) queue_ref(a)
+-#define queue_t_unref(a,b) queue_unref(a)
+-#define queues_t_link(c,q,tag) ao2_t_link(c,q,tag)
+-#define queues_t_unlink(c,q,tag) ao2_t_unlink(c,q,tag)
+-static inline struct call_queue *queue_ref(struct call_queue *q)
++/*!
++ * \brief ao2 callback to calculate hash of a queue by name
++ */
++static int qdata_hash_cb(const void *obj, const int flags)
+ {
+- ao2_ref(q, 1);
+- return q;
++ const struct queue_data *d = obj;
++ int qhash = d->qhash;
++
++ return qhash;
+ }
+
+-static inline struct call_queue *queue_unref(struct call_queue *q)
++
++/*!
++ * \brief ao2 callback to find queue by name
++ * \note this is the default function used by ao2_find
++ */
++static int qdata_cmp_cb(void *obj, void *arg, int flags)
+ {
+- ao2_ref(q, -1);
+- return NULL;
++ const struct queue_data *d = obj, *d2 = arg;
++ const char *name = arg;
++ int qhash = (flags & OBJ_POINTER) ? d2->qhash : ast_str_case_hash(name);
++
++ return (d->qhash == qhash) ? CMP_MATCH | CMP_STOP : 0;
+ }
+-#endif
+
+-/*! \brief Set variables of queue */
++/*! \brief Set channel variables of queue */
+ static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
+ {
+ char interfacevar[256]="";
+ float sl = 0;
++ struct queue_data *data = q->data;
+
+- ao2_lock(q);
+-
+ if (q->setqueuevar) {
+ sl = 0;
+- if (q->callscompleted > 0)
+- sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
++ ao2_lock(data);
++ if (data->callscompleted > 0) {
++ sl = 100 * ((float) data->callscompletedinsl / (float) data->callscompleted);
++ }
+
+ snprintf(interfacevar, sizeof(interfacevar),
+ "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
+- q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl);
++ q->name, q->maxlen, int2strat(q->strategy), data->count, data->holdtime, data->talktime,
++ data->callscompleted, data->callsabandoned, q->servicelevel, sl);
+
+- ao2_unlock(q);
+-
+- pbx_builtin_setvar_multiple(chan, interfacevar);
+- } else {
+- ao2_unlock(q);
++ pbx_builtin_setvar_multiple(chan, interfacevar);
++ ao2_unlock(data);
+ }
+ }
+
+-/*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
+-static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
++/*! \brief Insert the 'new' callattempt entry after the 'prev' entry of queue 'q' */
++static inline void insert_entry(struct queue_ent *new, int *pos)
+ {
+- struct queue_ent *cur;
++ new->pos = ++(*pos);
++ new->opos = *pos;
++ ao2_lock(new->parent->data);
++ new->parent->data->count++;
++ ao2_unlock(new->parent->data);
++}
+
+- if (!q || !new)
+- return;
+- if (prev) {
+- cur = prev->next;
+- prev->next = new;
+- } else {
+- cur = q->head;
+- q->head = new;
++/*! \brief return the device state for a member*/
++static int get_device_status(struct member *m)
++{
++ int ret;
++ struct mem_state *s = m->device;
++
++ ao2_lock(s);
++
++ ret = s->status;
++ switch (s->status) {
++ case AST_DEVICE_INVALID:
++ case AST_DEVICE_UNAVAILABLE:
++ case AST_DEVICE_BUSY:
++ break;
++ case AST_DEVICE_INUSE:
++ case AST_DEVICE_RINGING:
++ case AST_DEVICE_RINGINUSE:
++ case AST_DEVICE_ONHOLD:
++ /* if im active and may not place calls when INUSE im actually BUSY */
++ if ((s->reserved || s->active) && !m->callinuse) {
++ ret = AST_DEVICE_BUSY;
++ break;
++ }
++ break;
++ case AST_DEVICE_NOT_INUSE:
++ case AST_DEVICE_UNKNOWN:
++ /* it seems that i have this device active but the system does not */
++ if (s->active) {
++ ret = (m->callinuse) ? AST_DEVICE_INUSE : AST_DEVICE_BUSY;
++ } else if (s->reserved) {
++ ret = (m->callinuse) ? AST_DEVICE_RINGING : AST_DEVICE_BUSY;
++ }
+ }
+- new->next = cur;
++ ao2_unlock(s);
+
+- /* every queue_ent must have a reference to it's parent call_queue, this
+- * reference does not go away until the end of the queue_ent's life, meaning
+- * that even when the queue_ent leaves the call_queue this ref must remain. */
+- queue_ref(q);
+- new->parent = q;
+- new->pos = ++(*pos);
+- new->opos = *pos;
++ return ret;
+ }
+
+ /*! \brief Check if members are available
+@@ -1364,22 +1439,34 @@
+ * is available, the function immediately returns 0. If no members are available,
+ * then -1 is returned.
+ */
+-static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions)
++static int get_member_status(const struct queue_ent *qe, int join)
+ {
+ struct member *member;
+ struct ao2_iterator mem_iter;
++ struct call_queue *q = qe->parent;
++ int max_penalty = qe->max_penalty;
++ int min_penalty = qe->min_penalty;
++ enum empty_conditions conditions;
+
+- ao2_lock(q);
+- mem_iter = ao2_iterator_init(q->members, 0);
+- for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
++ conditions = (join) ? q->joinempty : q->leavewhenempty;
++
++ if (!conditions) {
++ return 0;
++ }
++
++ mem_iter = ao2_iterator_init(q->data->members, 0);
++ while((member = ao2_iterator_next(&mem_iter))) {
++ ao2_lock(member);
+ if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) {
+ if (conditions & QUEUE_EMPTY_PENALTY) {
+ ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
++ ao2_unlock(member);
++ ao2_ref(member, -1);
+ continue;
+ }
+ }
+
+- switch (member->status) {
++ switch (get_device_status(member)) {
+ case AST_DEVICE_INVALID:
+ if (conditions & QUEUE_EMPTY_INVALID) {
+ ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
+@@ -1393,6 +1480,7 @@
+ }
+ goto default_case;
+ case AST_DEVICE_INUSE:
++ case AST_DEVICE_BUSY:
+ if (conditions & QUEUE_EMPTY_INUSE) {
[... 8224 lines stripped ...]
More information about the asterisk-commits
mailing list