Merged revisions 378322 via svnmerge from
authorAutomerge script <automerge@asterisk.org>
Wed, 2 Jan 2013 18:20:03 +0000 (18:20 +0000)
committerAutomerge script <automerge@asterisk.org>
Wed, 2 Jan 2013 18:20:03 +0000 (18:20 +0000)
file:///srv/subversion/repos/asterisk/trunk

................
  r378322 | mjordan | 2013-01-02 12:11:59 -0600 (Wed, 02 Jan 2013) | 33 lines

  Prevent exhaustion of system resources through exploitation of event cache

  Asterisk maintains an internal cache for devices in the event subsystem. The
  device state cache holds the state of each device known to Asterisk, such that
  consumers of device state information can query for the last known state for
  a particular device, even if it is not part of an active call. The concept of
  a device in Asterisk can include entities that do not have a physical
  representation. One way that this occurred was when anonymous calls are allowed
  in Asterisk. A device was automatically created and stored in the cache for
  each anonymous call that occurred; this was possible in the SIP and IAX2
  channel drivers and through channel drivers that utilized the
  res_jabber/res_xmpp resource modules (Gtalk, Jingle, and Motif). These devices
  are never removed from the system, allowing anonymous calls to potentially
  exhaust a system's resources.

  This patch changes the event cache subsystem and device state management to
  no longer cache devices that are not associated with a physical entity.

  (issue ASTERISK-20175)
  Reported by: Russell Bryant, Leif Madsen, Joshua Colp
  Tested by: kmoore
  patches:
    event-cachability-3.diff uploaded by jcolp (license 5000)
  ........

  Merged revisions 378303 from http://svn.asterisk.org/svn/asterisk/branches/1.8
  ........

  Merged revisions 378320 from http://svn.asterisk.org/svn/asterisk/branches/10
  ........

  Merged revisions 378321 from http://svn.asterisk.org/svn/asterisk/branches/11
................

git-svn-id: https://origsvn.digium.com/svn/asterisk/team/mmichelson/threadpool@378329 65c4cc65-6c06-0410-ace0-fbb531ad65f3

22 files changed:
apps/app_confbridge.c
apps/app_meetme.c
apps/app_queue.c
apps/confbridge/conf_state_empty.c
channels/chan_agent.c
channels/chan_dahdi.c
channels/chan_iax2.c
channels/chan_local.c
channels/chan_sip.c
channels/chan_skinny.c
funcs/func_devstate.c
include/asterisk/channel.h
include/asterisk/devicestate.h
include/asterisk/event_defs.h
main/ccss.c
main/channel.c
main/channel_internal_api.c
main/devicestate.c
main/event.c
main/features.c
res/res_calendar.c
res/res_jabber.c

index 22e97f1..687830b 100644 (file)
@@ -1043,7 +1043,7 @@ int conf_add_post_join_action(struct conference_bridge_user *cbu, int (*func)(st
 
 void conf_handle_first_join(struct conference_bridge *conference_bridge)
 {
-       ast_devstate_changed(AST_DEVICE_INUSE, "confbridge:%s", conference_bridge->name);
+       ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "confbridge:%s", conference_bridge->name);
 }
 
 void conf_handle_second_active(struct conference_bridge *conference_bridge)
index 9346e7b..9c72abe 100644 (file)
@@ -2706,7 +2706,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
 
        /* This device changed state now - if this is the first user */
        if (conf->users == 1)
-               ast_devstate_changed(AST_DEVICE_INUSE, "meetme:%s", conf->confno);
+               ast_devstate_changed(AST_DEVICE_INUSE, (conf->isdynamic ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), "meetme:%s", conf->confno);
 
        ast_mutex_unlock(&conf->playlock);
 
@@ -4097,7 +4097,7 @@ bailoutandtrynormal:
 
                /* Change any states */
                if (!conf->users) {
-                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno);
+                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, (conf->isdynamic ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), "meetme:%s", conf->confno);
                }
 
                /* This flag is meant to kill a conference with only one participant remaining.  */
@@ -5592,8 +5592,8 @@ static void sla_change_trunk_state(const struct sla_trunk *trunk, enum sla_trunk
                                || trunk_ref == exclude)
                                continue;
                        trunk_ref->state = state;
-                       ast_devstate_changed(sla_state_to_devstate(state), 
-                               "SLA:%s_%s", station->name, trunk->name);
+                       ast_devstate_changed(sla_state_to_devstate(state), AST_DEVSTATE_CACHABLE,
+                                            "SLA:%s_%s", station->name, trunk->name);
                        break;
                }
        }
@@ -6091,8 +6091,8 @@ static void sla_handle_hold_event(struct sla_event *event)
 {
        ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
        event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
-       ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s", 
-               event->station->name, event->trunk_ref->trunk->name);
+       ast_devstate_changed(AST_DEVICE_ONHOLD, AST_DEVSTATE_CACHABLE, "SLA:%s_%s",
+                            event->station->name, event->trunk_ref->trunk->name);
        sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
                INACTIVE_TRUNK_REFS, event->trunk_ref);
 
@@ -6601,8 +6601,8 @@ static int sla_station_exec(struct ast_channel *chan, const char *data)
                        sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
                else {
                        trunk_ref->state = SLA_TRUNK_STATE_UP;
-                       ast_devstate_changed(AST_DEVICE_INUSE, 
-                               "SLA:%s_%s", station->name, trunk_ref->trunk->name);
+                       ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE,
+                                            "SLA:%s_%s", station->name, trunk_ref->trunk->name);
                }
        } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
                struct sla_ringing_trunk *ringing_trunk;
index eac4d2f..c0daff4 100644 (file)
@@ -1791,9 +1791,9 @@ static int handle_statechange(void *datap)
                if (found_member) {
                        found = 1;
                        if (avail) {
-                               ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Queue:%s_avail", q->name);
+                               ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
                        } else {
-                               ast_devstate_changed(AST_DEVICE_INUSE, "Queue:%s_avail", q->name);
+                               ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
                        }
                }
 
@@ -2083,7 +2083,7 @@ static void init_queue(struct call_queue *q)
         * AST_DEVICE_INUSE indicates no members are available.
         * AST_DEVICE_NOT_INUSE indicates a member is available.
         */
-       ast_devstate_changed(AST_DEVICE_INUSE, "Queue:%s_avail", q->name);
+       ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
 }
 
 static void clear_queue(struct call_queue *q)
@@ -2963,7 +2963,7 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *
                ast_copy_string(qe->context, q->context, sizeof(qe->context));
                q->count++;
                if (q->count == 1) {
-                       ast_devstate_changed(AST_DEVICE_RINGING, "Queue:%s", q->name);
+                       ast_devstate_changed(AST_DEVICE_RINGING, AST_DEVSTATE_CACHABLE, "Queue:%s", q->name);
                }
 
                res = 0;
@@ -3271,7 +3271,7 @@ static void leave_queue(struct queue_ent *qe)
                        char posstr[20];
                        q->count--;
                        if (!q->count) {
-                               ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Queue:%s", q->name);
+                               ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s", q->name);
                        }
 
                        /* Take us out of the queue */
@@ -3538,7 +3538,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
                        if (newstate != tmp->member->status) {
                                ast_log(LOG_WARNING, "Found a channel matching iterface %s while status was %s changed to %s\n",
                                        tmp->member->interface, ast_devstate2str(tmp->member->status), ast_devstate2str(newstate));
-                               ast_devstate_changed_literal(newstate, tmp->member->interface);
+                               ast_devstate_changed_literal(newstate, AST_DEVSTATE_CACHABLE, tmp->member->interface);
                        }
                }
                if ((tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
@@ -6027,7 +6027,7 @@ static int remove_from_queue(const char *queuename, const char *interface)
                        }
 
                        if (!num_available_members(q)) {
-                               ast_devstate_changed(AST_DEVICE_INUSE, "Queue:%s_avail", q->name);
+                               ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
                        }
 
                        res = RES_OKAY;
@@ -6104,7 +6104,7 @@ static int add_to_queue(const char *queuename, const char *interface, const char
                                new_member->status, new_member->paused);
 
                        if (is_member_available(new_member)) {
-                               ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Queue:%s_avail", q->name);
+                               ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
                        }
 
                        ao2_ref(new_member, -1);
@@ -6175,9 +6175,9 @@ static int set_member_paused(const char *queuename, const char *interface, const
                                }
 
                                if (is_member_available(mem)) {
-                                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Queue:%s_avail", q->name);
+                                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
                                } else if (!num_available_members(q)) {
-                                       ast_devstate_changed(AST_DEVICE_INUSE, "Queue:%s_avail", q->name);
+                                       ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
                                }
 
                                ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, ""));
index 22997ad..afc736d 100644 (file)
@@ -81,6 +81,6 @@ static void join_marked(struct conference_bridge_user *cbu)
 static void transition_to_empty(struct conference_bridge_user *cbu)
 {
        /* Set device state to "not in use" */
-       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "confbridge:%s", cbu->conference_bridge->name);
+       ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "confbridge:%s", cbu->conference_bridge->name);
        conf_ended(cbu->conference_bridge);
 }
index 42492f4..a9a70d0 100644 (file)
@@ -618,7 +618,7 @@ static struct ast_frame *agent_read(struct ast_channel *ast)
                if (p->chan) {
                        ast_channel_internal_bridged_channel_set(p->chan, NULL);
                        p->chan = NULL;
-                       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
+                       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
                        p->acknowledged = 0;
                }
        } else {
@@ -875,7 +875,7 @@ static int agent_call(struct ast_channel *ast, const char *dest, int timeout)
        } else {
                /* Agent hung-up */
                p->chan = NULL;
-               ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
+               ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
        }
 
        if (!res) {
@@ -995,7 +995,7 @@ static int agent_hangup(struct ast_channel *ast)
        if (!p->loginstart) {
                p->logincallerid[0] = '\0';
        } else {
-               ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
+               ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
        }
 
        if (p->abouttograb) {
@@ -2143,7 +2143,7 @@ static int login_exec(struct ast_channel *chan, const char *data)
                                                }
                                                ast_mutex_unlock(&p->lock);
                                                AST_LIST_UNLOCK(&agents);
-                                               ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
+                                               ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
                                                while (res >= 0) {
                                                        ast_mutex_lock(&p->lock);
                                                        if (p->deferlogoff && p->chan) {
@@ -2164,7 +2164,7 @@ static int login_exec(struct ast_channel *chan, const char *data)
                                                                if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
                                                                        ast_debug(1, "Wrapup time for %s expired!\n", p->agent);
                                                                        p->lastdisc = ast_tv(0, 0);
-                                                                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
+                                                                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
                                                                        if (p->ackcall) {
                                                                                check_beep(p, 0);
                                                                        } else {
@@ -2235,7 +2235,7 @@ static int login_exec(struct ast_channel *chan, const char *data)
                                                ast_queue_log("NONE", ast_channel_uniqueid(chan), agent, "AGENTLOGOFF", "%s|%ld", ast_channel_name(chan), logintime);
                                                ast_verb(2, "Agent '%s' logged out\n", p->agent);
                                                /* If there is no owner, go ahead and kill it now */
-                                               ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
+                                               ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
                                                if (p->dead && !p->owner) {
                                                        ast_mutex_destroy(&p->lock);
                                                        ast_cond_destroy(&p->app_complete_cond);
index ce2d233..84b3089 100644 (file)
@@ -3478,7 +3478,7 @@ static void dahdi_pri_update_span_devstate(struct sig_pri_span *pri)
        }
        if (pri->congestion_devstate != new_state) {
                pri->congestion_devstate = new_state;
-               ast_devstate_changed(AST_DEVICE_UNKNOWN, "DAHDI/I%d/congestion", pri->span);
+               ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_NOT_CACHABLE, "DAHDI/I%d/congestion", pri->span);
        }
 #if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
        /* Update the span threshold device state and report any change. */
@@ -3494,7 +3494,7 @@ static void dahdi_pri_update_span_devstate(struct sig_pri_span *pri)
        }
        if (pri->threshold_devstate != new_state) {
                pri->threshold_devstate = new_state;
-               ast_devstate_changed(AST_DEVICE_UNKNOWN, "DAHDI/I%d/threshold", pri->span);
+               ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_NOT_CACHABLE, "DAHDI/I%d/threshold", pri->span);
        }
 #endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
 }
@@ -10037,7 +10037,8 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
        if (dashptr) {
                *dashptr = '\0';
        }
-       ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, device_name);
+       ast_set_flag(ast_channel_flags(tmp), AST_FLAG_DISABLE_DEVSTATE_CACHE);
+       ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, AST_DEVSTATE_NOT_CACHABLE, device_name);
 
        for (v = i->vars ; v ; v = v->next)
                pbx_builtin_setvar_helper(tmp, v->name, v->value);
index 7a2528f..42588b1 100644 (file)
@@ -5819,7 +5819,7 @@ static int iax2_getpeertrunk(struct sockaddr_in sin)
 }
 
 /*! \brief  Create new call, interface with the PBX core */
-static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capability, const char *linkedid)
+static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capability, const char *linkedid, unsigned int cachable)
 {
        struct ast_channel *tmp;
        struct chan_iax2_pvt *i;
@@ -5901,6 +5901,10 @@ static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capab
        i->owner = tmp;
        i->capability = capability;
 
+       if (!cachable) {
+               ast_set_flag(ast_channel_flags(tmp), AST_FLAG_DISABLE_DEVSTATE_CACHE);
+       }
+
        /* Set inherited variables */
        if (i->vars) {
                for (v = i->vars ; v ; v = v->next)
@@ -8182,7 +8186,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
                /* if challenge has been sent, but no challenge response if given, reject. */
                goto return_unref;
        }
-       ast_devstate_changed(AST_DEVICE_UNKNOWN, "IAX2/%s", p->name); /* Activate notification */
+       ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */
 
        /* either Authentication has taken place, or a REGAUTH must be sent before verifying registration */
        res = 0;
@@ -8736,7 +8740,7 @@ static void __expire_registry(const void *data)
        if (!ast_test_flag64(peer, IAX_TEMPONLY))
                ast_db_del("IAX/Registry", peer->name);
        register_peer_exten(peer, 0);
-       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", peer->name); /* Activate notification */
+       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
        if (iax2_regfunk)
                iax2_regfunk(peer->name, 0);
 
@@ -8791,7 +8795,7 @@ static void reg_source_db(struct iax2_peer *p)
                }
        }
 
-       ast_devstate_changed(AST_DEVICE_UNKNOWN, "IAX2/%s", p->name); /* Activate notification */
+       ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */
 
        p->expire = iax2_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, peer_ref(p));
        if (p->expire == -1) {
@@ -8868,14 +8872,14 @@ static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, i
                                            ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
                        manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Registered\r\nAddress: %s\r\nPort: %d\r\n", p->name, ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
                        register_peer_exten(p, 1);
-                       ast_devstate_changed(AST_DEVICE_UNKNOWN, "IAX2/%s", p->name); /* Activate notification */
+                       ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */
                } else if (!ast_test_flag64(p, IAX_TEMPONLY)) {
                        ast_verb(3, "Unregistered IAX2 '%s' (%s)\n", p->name,
                                            ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED");
                        manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Unregistered\r\n", p->name);
                        register_peer_exten(p, 0);
                        ast_db_del("IAX/Registry", p->name);
-                       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", p->name); /* Activate notification */
+                       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */
                }
                /* Update the host */
                /* Verify that the host is really there */
@@ -10441,7 +10445,8 @@ static int socket_process_helper(struct iax2_thread *thread)
                    (f.frametype == AST_FRAME_IAX)) {
                        if (ast_test_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART)) {
                                ast_clear_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART);
-                               if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat, NULL)) {
+                               if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat, NULL,
+                                                 ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED))) {
                                        ast_variables_destroy(ies.vars);
                                        ast_mutex_unlock(&iaxsl[fr->callno]);
                                        return 1;
@@ -11083,13 +11088,13 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                if (iaxs[fr->callno]->pingtime <= peer->maxms) {
                                                        ast_log(LOG_NOTICE, "Peer '%s' is now REACHABLE! Time: %d\n", peer->name, iaxs[fr->callno]->pingtime);
                                                        manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Reachable\r\nTime: %d\r\n", peer->name, iaxs[fr->callno]->pingtime); 
-                                                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "IAX2/%s", peer->name); /* Activate notification */
+                                                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
                                                }
                                        } else if ((peer->historicms > 0) && (peer->historicms <= peer->maxms)) {
                                                if (iaxs[fr->callno]->pingtime > peer->maxms) {
                                                        ast_log(LOG_NOTICE, "Peer '%s' is now TOO LAGGED (%d ms)!\n", peer->name, iaxs[fr->callno]->pingtime);
                                                        manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Lagged\r\nTime: %d\r\n", peer->name, iaxs[fr->callno]->pingtime); 
-                                                       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", peer->name); /* Activate notification */
+                                                       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
                                                }
                                        }
                                        peer->lastms = iaxs[fr->callno]->pingtime;
@@ -11333,7 +11338,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                                        using_prefs);
 
                                                        ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
-                                                       if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format, NULL)))
+                                                       if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format, NULL, 1)))
                                                                iax2_destroy(fr->callno);
                                                        else if (ies.vars) {
                                                                struct ast_datastore *variablestore;
@@ -11404,7 +11409,7 @@ immediatedial:
                                                        iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat));
                                                ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
                                                send_command(iaxs[fr->callno], AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, 0, NULL, 0, -1);
-                                               if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->peerformat, NULL)))
+                                               if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->peerformat, NULL, 1)))
                                                        iax2_destroy(fr->callno);
                                                else if (ies.vars) {
                                                        struct ast_datastore *variablestore;
@@ -12171,7 +12176,7 @@ static void __iax2_poke_noanswer(const void *data)
        if (peer->lastms > -1) {
                ast_log(LOG_NOTICE, "Peer '%s' is now UNREACHABLE! Time: %d\n", peer->name, peer->lastms);
                manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Unreachable\r\nTime: %d\r\n", peer->name, peer->lastms);
-               ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", peer->name); /* Activate notification */
+               ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
        }
        if ((callno = peer->callno) > 0) {
                ast_mutex_lock(&iaxsl[callno]);
@@ -12345,7 +12350,8 @@ static struct ast_channel *iax2_request(const char *type, struct ast_format_cap
                ast_string_field_set(iaxs[callno], host, pds.peer);
        }
 
-       c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability, requestor ? ast_channel_linkedid(requestor) : NULL);
+       c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability, requestor ? ast_channel_linkedid(requestor) : NULL, cai.found);
+
        ast_mutex_unlock(&iaxsl[callno]);
 
        if (c) {
index 1491279..7fa6bf5 100644 (file)
@@ -1271,6 +1271,9 @@ static struct ast_channel *local_new(struct local_pvt *p, int state, const char
        ast_channel_tech_pvt_set(tmp, p);
        ast_channel_tech_pvt_set(tmp2, p);
 
+       ast_set_flag(ast_channel_flags(tmp), AST_FLAG_DISABLE_DEVSTATE_CACHE);
+       ast_set_flag(ast_channel_flags(tmp2), AST_FLAG_DISABLE_DEVSTATE_CACHE);
+
        p->owner = tmp;
        p->chan = tmp2;
 
index b2b3395..18c14ea 100644 (file)
@@ -6854,7 +6854,7 @@ static int update_call_counter(struct sip_pvt *fup, int event)
        }
 
        if (p) {
-               ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", p->name);
+               ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", p->name);
                sip_unref_peer(p, "update_call_counter: sip_unref_peer from call counter");
        }
        return 0;
@@ -8115,6 +8115,9 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
                ast_jb_configure(tmp, &global_jbconf);
        }
 
+       if (!i->relatedpeer) {
+               ast_set_flag(ast_channel_flags(tmp), AST_FLAG_DISABLE_DEVSTATE_CACHE);
+       }
        /* Set channel variables for this call from configuration */
        for (v = i->chanvars ; v ; v = v->next) {
                char valuebuf[1024];
@@ -15668,7 +15671,7 @@ static int expire_register(const void *data)
 
        manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Unregistered\r\nCause: Expired\r\n", peer->name);
        register_peer_exten(peer, FALSE);       /* Remove regexten */
-       ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
+       ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", peer->name);
 
        /* Do we need to release this peer from memory?
                Only for realtime peers and autocreated peers
@@ -16459,8 +16462,9 @@ static void sip_peer_hold(struct sip_pvt *p, int hold)
        ast_atomic_fetchadd_int(&p->relatedpeer->onhold, (hold ? +1 : -1));
 
        /* Request device state update */
-       ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", p->relatedpeer->name);
-       
+       ast_devstate_changed(AST_DEVICE_UNKNOWN, (ast_test_flag(ast_channel_flags(p->owner), AST_FLAG_DISABLE_DEVSTATE_CACHE) ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE),
+                            "SIP/%s", p->relatedpeer->name);
+
        return;
 }
 
@@ -16983,7 +16987,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
                } else {
                        update_peer_lastmsgssent(peer, -1, 0);
                }
-               ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
+               ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", peer->name);
        }
        if (res < 0) {
                switch (res) {
@@ -23439,7 +23443,7 @@ static void handle_response_peerpoke(struct sip_pvt *p, int resp, struct sip_req
 
                ast_log(LOG_NOTICE, "Peer '%s' is now %s. (%dms / %dms)\n",
                        peer->name, s, pingtime, peer->maxms);
-               ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
+               ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", peer->name);
                if (sip_cfg.peer_rtupdate) {
                        ast_update_realtime(ast_check_realtime("sipregs") ? "sipregs" : "sippeers", "name", peer->name, "lastms", str_lastms, SENTINEL);
                }
@@ -29350,7 +29354,7 @@ static int sip_poke_noanswer(const void *data)
        /* Don't send a devstate change if nothing changed. */
        if (peer->lastms > -1) {
                peer->lastms = -1;
-               ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
+               ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", peer->name);
        }
 
        /* Try again quickly */
index 2e43411..a11cac6 100644 (file)
@@ -2145,7 +2145,7 @@ static int skinny_register(struct skinny_req *req, struct skinnysession *s)
                                AST_LIST_TRAVERSE(&l->sublines, subline, list) {
                                        ast_extension_state_add(subline->context, subline->exten, skinny_extensionstate_cb, subline->container);
                                }
-                               ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s", l->name);
+                               ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
                                --instance;
                        }
                        break;
@@ -2180,7 +2180,7 @@ static int skinny_unregister(struct skinny_req *req, struct skinnysession *s)
                                l->instance = 0;
                                manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: Skinny\r\nPeer: Skinny/%s@%s\r\nPeerStatus: Unregistered\r\n", l->name, d->name);
                                unregister_exten(l);
-                               ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Skinny/%s", l->name);
+                               ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
                        }
                }
        }
@@ -5947,7 +5947,7 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
                        event, d->name, instance, callreference);
                break;
        }
-       ast_devstate_changed(AST_DEVICE_UNKNOWN, "Skinny/%s", l->name);
+       ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
 
        return 1;
 }
@@ -5987,7 +5987,7 @@ static int handle_offhook_message(struct skinny_req *req, struct skinnysession *
        transmit_ringer_mode(d, SKINNY_RING_OFF);
        d->hookstate = SKINNY_OFFHOOK;
 
-       ast_devstate_changed(AST_DEVICE_INUSE, "Skinny/%s", l->name);
+       ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
 
        if (sub && sub->substate == SUBSTATE_HOLD) {
                return 1;
@@ -6054,7 +6054,7 @@ static int handle_onhook_message(struct skinny_req *req, struct skinnysession *s
                return 0;
        }
        
-       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s", l->name);
+       ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
        
        dumpsub(sub, 0);
 
@@ -6390,7 +6390,7 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
                return 0;
        }
 
-       ast_devstate_changed(AST_DEVICE_INUSE, "Skinny/%s", l->name);
+       ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
 
        switch(event) {
        case SOFTKEY_NONE:
@@ -6544,8 +6544,8 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
                        return 0;
                }
        
-               ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s", l->name);
-       
+               ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
+
                if (sub) {
                        dumpsub(sub, 1);
                } else { /* No sub, maybe an SLA call */
index e1f3438..6472610 100644 (file)
@@ -132,7 +132,7 @@ static int devstate_write(struct ast_channel *chan, const char *cmd, char *data,
 
        ast_db_put(astdb_family, data, value);
 
-       ast_devstate_changed(state_val, "Custom:%s", data);
+       ast_devstate_changed(state_val, AST_DEVSTATE_CACHABLE, "Custom:%s", data);
 
        return 0;
 }
@@ -295,7 +295,7 @@ static char *handle_cli_devstate_change(struct ast_cli_entry *e, int cmd, struct
 
        ast_db_put(astdb_family, dev, state);
 
-       ast_devstate_changed(state_val, "Custom:%s", dev);
+       ast_devstate_changed(state_val, AST_DEVSTATE_CACHABLE, "Custom:%s", dev);
 
        return CLI_SUCCESS;
 }
@@ -341,7 +341,7 @@ static int load_module(void)
                if (dev_name <= (const char *) 1)
                        continue;
                ast_devstate_changed(ast_devstate_val(db_entry->data),
-                       "Custom:%s\n", dev_name);
+                       AST_DEVSTATE_CACHABLE, "Custom:%s\n", dev_name);
        }
        ast_db_freetree(db_tree);
        db_tree = NULL;
index 0157d76..9b40866 100644 (file)
@@ -903,6 +903,12 @@ enum {
         *  some non-traditional dialplans (like AGI) to continue to function.
         */
        AST_FLAG_DISABLE_WORKAROUNDS = (1 << 20),
+       /*! Disable device state event caching.  This allows allows channel
+        * drivers to selectively prevent device state events from being cached
+        * by certain channels such as anonymous calls which have no persistent
+        * represenatation that can be tracked.
+        */
+       AST_FLAG_DISABLE_DEVSTATE_CACHE = (1 << 21),
 };
 
 /*! \brief ast_bridge_config flags */
index 66ca2bd..86740bc 100644 (file)
@@ -61,6 +61,14 @@ enum ast_device_state {
        AST_DEVICE_TOTAL,        /*/ Total num of device states, used for testing */
 };
 
+/*! \brief Device State Cachability
+ *  \note This is used to define the cachability of a device state when set.
+ */
+enum ast_devstate_cache {
+       AST_DEVSTATE_NOT_CACHABLE,  /*!< This device state is not cachable */
+       AST_DEVSTATE_CACHABLE,      /*!< This device state is cachable */
+};
+
 /*! \brief Devicestate provider call back */
 typedef enum ast_device_state (*ast_devstate_prov_cb_type)(const char *data);
 
@@ -129,6 +137,7 @@ enum ast_device_state ast_device_state(const char *device);
  * \brief Tells Asterisk the State for Device is changed
  *
  * \param state the new state of the device
+ * \param cachable whether this device state is cachable
  * \param fmt device name like a dial string with format parameters
  *
  * The new state of the device will be sent off to any subscribers
@@ -138,13 +147,14 @@ enum ast_device_state ast_device_state(const char *device);
  * \retval 0 on success
  * \retval -1 on failure
  */
-int ast_devstate_changed(enum ast_device_state state, const char *fmt, ...)
-       __attribute__((format(printf, 2, 3)));
+int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt, ...)
+       __attribute__((format(printf, 3, 4)));
 
 /*!
  * \brief Tells Asterisk the State for Device is changed
  *
  * \param state the new state of the device
+ * \param cachable whether this device state is cachable
  * \param device device name like a dial string with format parameters
  *
  * The new state of the device will be sent off to any subscribers
@@ -154,7 +164,7 @@ int ast_devstate_changed(enum ast_device_state state, const char *fmt, ...)
  * \retval 0 on success
  * \retval -1 on failure
  */
-int ast_devstate_changed_literal(enum ast_device_state state, const char *device);
+int ast_devstate_changed_literal(enum ast_device_state state, enum ast_devstate_cache cachable, const char *device);
 
 /*!
  * \brief Tells Asterisk the State for Device is changed.
index d3514f5..10c76d0 100644 (file)
@@ -298,8 +298,14 @@ enum ast_event_ie_type {
        AST_EVENT_IE_PRESENCE_SUBTYPE    = 0x003b,
        AST_EVENT_IE_PRESENCE_MESSAGE    = 0x003c,
 
+       /*!
+        * \brief Event non-cachability flag
+        * Used by: All events
+        * Payload type: UINT
+        */
+       AST_EVENT_IE_CACHABLE            = 0x003d,
        /*! \brief Must be the last IE value +1 */
-       AST_EVENT_IE_TOTAL               = 0x003d,
+       AST_EVENT_IE_TOTAL               = 0x003e,
 };
 
 /*!
index 6ce022d..b479a3c 100644 (file)
@@ -649,7 +649,7 @@ static void ccss_notify_device_state_change(const char *device, enum cc_state st
                "Notification of CCSS state change to '%s', device state '%s' for device '%s'\n",
                cc_state_to_string(state), ast_devstate2str(devstate), device);
 
-       ast_devstate_changed(devstate, "ccss:%s", device);
+       ast_devstate_changed(devstate, AST_DEVSTATE_CACHABLE, "ccss:%s", device);
 }
 
 #define CC_OFFER_TIMER_DEFAULT                 20              /* Seconds */
index 38d11b1..d1d4d09 100644 (file)
@@ -2482,7 +2482,7 @@ static void ast_channel_destructor(void *obj)
                 * instance is dead, we don't know the state of all other possible
                 * instances.
                 */
-               ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, device_name);
+               ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE) ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), device_name);
        }
 
        ast_channel_nativeformats_set(chan, ast_format_cap_destroy(ast_channel_nativeformats(chan)));
@@ -7401,7 +7401,7 @@ int ast_setstate(struct ast_channel *chan, enum ast_channel_state state)
        /* We have to pass AST_DEVICE_UNKNOWN here because it is entirely possible that the channel driver
         * for this channel is using the callback method for device state. If we pass in an actual state here
         * we override what they are saying the state is and things go amuck. */
-       ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, name);
+       ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE) ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), name);
 
        /* setstate used to conditionally report Newchannel; this is no more */
        /*** DOCUMENTATION
index c7ed84c..3f892dd 100644 (file)
@@ -263,6 +263,7 @@ static void channel_data_add_flags(struct ast_data *tree,
        ast_data_add_bool(tree, "BRIDGE_HANGUP_RUN", ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_RUN));
        ast_data_add_bool(tree, "BRIDGE_HANGUP_DONT", ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT));
        ast_data_add_bool(tree, "DISABLE_WORKAROUNDS", ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS));
+       ast_data_add_bool(tree, "DISABLE_DEVSTATE_CACHE", ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE));
 }
 
 int ast_channel_data_add_structure(struct ast_data *tree,
index 3256a7b..4ed51f9 100644 (file)
@@ -174,6 +174,7 @@ static AST_RWLIST_HEAD_STATIC(devstate_provs, devstate_prov);
 
 struct state_change {
        AST_LIST_ENTRY(state_change) list;
+       enum ast_devstate_cache cachable;
        char device[1];
 };
 
@@ -191,6 +192,7 @@ struct devstate_change {
        AST_LIST_ENTRY(devstate_change) entry;
        uint32_t state;
        struct ast_eid eid;
+       enum ast_devstate_cache cachable;
        char device[1];
 };
 
@@ -424,7 +426,7 @@ static int getproviderstate(const char *provider, const char *address)
        return res;
 }
 
-static void devstate_event(const char *device, enum ast_device_state state)
+static void devstate_event(const char *device, enum ast_device_state state, int cachable)
 {
        struct ast_event *event;
        enum ast_event_type event_type;
@@ -440,18 +442,23 @@ static void devstate_event(const char *device, enum ast_device_state state)
        ast_debug(3, "device '%s' state '%d'\n", device, state);
 
        if (!(event = ast_event_new(event_type,
-                       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
-                       AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
-                       AST_EVENT_IE_END))) {
+                                   AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
+                                   AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
+                                   AST_EVENT_IE_CACHABLE, AST_EVENT_IE_PLTYPE_UINT, cachable,
+                                   AST_EVENT_IE_END))) {
                return;
        }
 
-       ast_event_queue_and_cache(event);
+       if (cachable) {
+               ast_event_queue_and_cache(event);
+       } else {
+               ast_event_queue(event);
+       }
 }
 
 /*! Called by the state change thread to find out what the state is, and then
  *  to queue up the state change event */
-static void do_state_change(const char *device)
+static void do_state_change(const char *device, int cachable)
 {
        enum ast_device_state state;
 
@@ -459,10 +466,10 @@ static void do_state_change(const char *device)
 
        ast_debug(3, "Changing state for %s - state %d (%s)\n", device, state, ast_devstate2str(state));
 
-       devstate_event(device, state);
+       devstate_event(device, state, cachable);
 }
 
-int ast_devstate_changed_literal(enum ast_device_state state, const char *device)
+int ast_devstate_changed_literal(enum ast_device_state state, enum ast_devstate_cache cachable, const char *device)
 {
        struct state_change *change;
 
@@ -483,14 +490,15 @@ int ast_devstate_changed_literal(enum ast_device_state state, const char *device
         */
 
        if (state != AST_DEVICE_UNKNOWN) {
-               devstate_event(device, state);
+               devstate_event(device, state, cachable);
        } else if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) {
                /* we could not allocate a change struct, or */
                /* there is no background thread, so process the change now */
-               do_state_change(device);
+               do_state_change(device, cachable);
        } else {
                /* queue the change */
                strcpy(change->device, device);
+               change->cachable = cachable;
                AST_LIST_LOCK(&state_changes);
                AST_LIST_INSERT_TAIL(&state_changes, change, list);
                ast_cond_signal(&change_pending);
@@ -502,10 +510,10 @@ int ast_devstate_changed_literal(enum ast_device_state state, const char *device
 
 int ast_device_state_changed_literal(const char *dev)
 {
-       return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, dev);
+       return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, dev);
 }
 
-int ast_devstate_changed(enum ast_device_state state, const char *fmt, ...)
+int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt, ...)
 {
        char buf[AST_MAX_EXTENSION];
        va_list ap;
@@ -514,7 +522,7 @@ int ast_devstate_changed(enum ast_device_state state, const char *fmt, ...)
        vsnprintf(buf, sizeof(buf), fmt, ap);
        va_end(ap);
 
-       return ast_devstate_changed_literal(state, buf);
+       return ast_devstate_changed_literal(state, cachable, buf);
 }
 
 int ast_device_state_changed(const char *fmt, ...)
@@ -526,7 +534,7 @@ int ast_device_state_changed(const char *fmt, ...)
        vsnprintf(buf, sizeof(buf), fmt, ap);
        va_end(ap);
 
-       return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, buf);
+       return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, buf);
 }
 
 /*! \brief Go through the dev state change queue and update changes in the dev state thread */
@@ -546,7 +554,7 @@ static void *do_devstate_changes(void *data)
                /* Process each state change */
                while ((current = next)) {
                        next = AST_LIST_NEXT(current, list);
-                       do_state_change(current->device);
+                       do_state_change(current->device, current->cachable);
                        ast_free(current);
                }
        }
@@ -590,7 +598,7 @@ static void devstate_cache_cb(const struct ast_event *event, void *data)
        collection->num_states++;
 }
 
-static void process_collection(const char *device, struct change_collection *collection)
+static void process_collection(const char *device, enum ast_devstate_cache cachable, struct change_collection *collection)
 {
        int i;
        struct ast_devstate_aggregate agg;
@@ -641,7 +649,11 @@ static void process_collection(const char *device, struct change_collection *col
                return;
        }
 
-       ast_event_queue_and_cache(event);
+       if (cachable) {
+               ast_event_queue_and_cache(event);
+       } else {
+               ast_event_queue(event);
+       }
 }
 
 static void handle_devstate_change(struct devstate_change *sc)
@@ -667,7 +679,7 @@ static void handle_devstate_change(struct devstate_change *sc)
        /* Populate the collection of device states from the cache */
        ast_event_dump_cache(tmp_sub);
 
-       process_collection(sc->device, &collection);
+       process_collection(sc->device, sc->cachable, &collection);
 
        ast_event_sub_destroy(tmp_sub);
 }
@@ -696,10 +708,12 @@ static void devstate_change_collector_cb(const struct ast_event *event, void *da
        const char *device;
        const struct ast_eid *eid;
        uint32_t state;
+       enum ast_devstate_cache cachable = AST_DEVSTATE_CACHABLE;
 
        device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
        eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID);
        state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
+       cachable = ast_event_get_ie_uint(event, AST_EVENT_IE_CACHABLE);
 
        if (ast_strlen_zero(device) || !eid) {
                ast_log(LOG_ERROR, "Invalid device state change event received\n");
@@ -712,6 +726,7 @@ static void devstate_change_collector_cb(const struct ast_event *event, void *da
        strcpy(sc->device, device);
        sc->eid = *eid;
        sc->state = state;
+       sc->cachable = cachable;
 
        ast_mutex_lock(&devstate_collector.lock);
        AST_LIST_INSERT_TAIL(&devstate_collector.devstate_change_q, sc, entry);
index 2c4670b..34ba019 100644 (file)
@@ -279,7 +279,7 @@ static const struct ie_map {
        [AST_EVENT_IE_RECEIVED_HASH]       = { AST_EVENT_IE_PLTYPE_STR,  "ReceivedHash" },
        [AST_EVENT_IE_USING_PASSWORD]      = { AST_EVENT_IE_PLTYPE_UINT, "UsingPassword" },
        [AST_EVENT_IE_ATTEMPTED_TRANSPORT] = { AST_EVENT_IE_PLTYPE_STR,  "AttemptedTransport" },
-
+       [AST_EVENT_IE_CACHABLE]            = { AST_EVENT_IE_PLTYPE_UINT,  "Cachable" },
 };
 
 const char *ast_event_get_type_name(const struct ast_event *event)
index 5e544cc..44f140e 100644 (file)
@@ -1257,7 +1257,7 @@ static void notify_metermaids(const char *exten, char *context, enum ast_device_
        ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'",
                exten, context, ast_devstate2str(state));
 
-       ast_devstate_changed(state, "park:%s@%s", exten, context);
+       ast_devstate_changed(state, AST_DEVSTATE_CACHABLE, "park:%s@%s", exten, context);
 }
 
 /*! \brief metermaids callback from devicestate.c */
index ed441d1..fd42375 100644 (file)
@@ -620,9 +620,9 @@ static struct ast_calendar_event *destroy_event(struct ast_calendar_event *event
         * but haven't hit the end event yet, go ahead and set the devicestate to the current busy status */
        if (event->bs_start_sched < 0 && event->bs_end_sched >= 0) {
                if (!calendar_is_busy(event->owner)) {
-                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Calendar:%s", event->owner->name);
+                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name);
                } else {
-                       ast_devstate_changed(AST_DEVICE_BUSY, "Calendar:%s", event->owner->name);
+                       ast_devstate_changed(AST_DEVICE_BUSY, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name);
                }
        }
 
@@ -880,9 +880,9 @@ static int calendar_devstate_change(const void *data)
        /* We can have overlapping events, so ignore the event->busy_state and check busy state
         * based on all events in the calendar */
        if (!calendar_is_busy(event->owner)) {
-               ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Calendar:%s", event->owner->name);
+               ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name);
        } else {
-               ast_devstate_changed(AST_DEVICE_BUSY, "Calendar:%s", event->owner->name);
+               ast_devstate_changed(AST_DEVICE_BUSY, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name);
        }
 
        event = ast_calendar_unref_event(event);
index fa45fdf..f74d6ac 100644 (file)
@@ -361,7 +361,7 @@ static char *aji_cli_create_leafnode(struct ast_cli_entry *e, int cmd,
 static void aji_create_affiliations(struct aji_client *client, const char *node);
 static iks* aji_pubsub_iq_create(struct aji_client *client, const char *type);
 static void aji_publish_device_state(struct aji_client *client, const char * device,
-       const char *device_state);
+                                    const char *device_state, unsigned int cachable);
 static int aji_handle_pubsub_error(void *data, ikspak *pak);
 static int aji_handle_pubsub_event(void *data, ikspak *pak);
 static void aji_pubsub_subscribe(struct aji_client *client, const char *node);
@@ -375,7 +375,7 @@ static void aji_publish_mwi(struct aji_client *client, const char *mailbox,
 static void aji_devstate_cb(const struct ast_event *ast_event, void *data);
 static void aji_mwi_cb(const struct ast_event *ast_event, void *data);
 static iks* aji_build_publish_skeleton(struct aji_client *client, const char *node,
-       const char *event_type);
+                                      const char *event_type, unsigned int cachable);
 /* No transports in this version */
 /*
 static int aji_create_transport(char *label, struct aji_client *client);
@@ -3275,6 +3275,7 @@ static void aji_devstate_cb(const struct ast_event *ast_event, void *data)
 {
        const char *device;
        const char *device_state;
+       unsigned int cachable;
        struct aji_client *client;
        if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID)))
        {
@@ -3286,7 +3287,8 @@ static void aji_devstate_cb(const struct ast_event *ast_event, void *data)
        client = ASTOBJ_REF((struct aji_client *) data);
        device = ast_event_get_ie_str(ast_event, AST_EVENT_IE_DEVICE);
        device_state = ast_devstate_str(ast_event_get_ie_uint(ast_event, AST_EVENT_IE_STATE));
-       aji_publish_device_state(client, device, device_state);
+       cachable = ast_event_get_ie_uint(ast_event, AST_EVENT_IE_CACHABLE);
+       aji_publish_device_state(client, device, device_state, cachable);
        ASTOBJ_UNREF(client, ast_aji_client_destroy);
 }
 
@@ -3327,11 +3329,13 @@ static void aji_init_event_distribution(struct aji_client *client)
  */
 static int aji_handle_pubsub_event(void *data, ikspak *pak)
 {
-       char *item_id, *device_state, *context;
+       char *item_id, *device_state, *context, *cachable_str;
        int oldmsgs, newmsgs;
        iks *item, *item_content;
        struct ast_eid pubsub_eid;
        struct ast_event *event;
+       unsigned int cachable = AST_DEVSTATE_CACHABLE;
+
        item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item");
        if (!item) {
                ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n");
@@ -3346,11 +3350,14 @@ static int aji_handle_pubsub_event(void *data, ikspak *pak)
        }
        if (!strcasecmp(iks_name(item_content), "state")) {
                device_state = iks_find_cdata(item, "state");
+               if ((cachable_str = iks_find_cdata(item, "cachable"))) {
+                       sscanf(cachable_str, "%30d", &cachable);
+               }
                if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE,
-                       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE,
-                       AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID,
-                       AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
-                       AST_EVENT_IE_END))) {
+                                           AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE,
+                                           AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID,
+                                           AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
+                                           AST_EVENT_IE_END))) {
                        return IKS_FILTER_EAT;
                }
        } else if (!strcasecmp(iks_name(item_content), "mailbox")) {
@@ -3370,7 +3377,13 @@ static int aji_handle_pubsub_event(void *data, ikspak *pak)
                        iks_name(item_content));
                return IKS_FILTER_EAT;
        }
-       ast_event_queue_and_cache(event);
+
+       if (cachable == AST_DEVSTATE_CACHABLE) {
+               ast_event_queue_and_cache(event);
+       } else {
+               ast_event_queue(event);
+       }
+
        return IKS_FILTER_EAT;
 }
 
@@ -3445,7 +3458,7 @@ static void aji_pubsub_subscribe(struct aji_client *client, const char *node)
  * \return iks *
  */
 static iks* aji_build_publish_skeleton(struct aji_client *client, const char *node,
-       const char *event_type)
+                                      const char *event_type, unsigned int cachable)
 {
        iks *request = aji_pubsub_iq_create(client, "set");
        iks *pubsub, *publish, *item;
@@ -3459,8 +3472,24 @@ static iks* aji_build_publish_skeleton(struct aji_client *client, const char *no
        }
        item = iks_insert(publish, "item");
        iks_insert_attrib(item, "id", node);
-       return item;
 
+       if (cachable == AST_DEVSTATE_NOT_CACHABLE) {
+               iks *options, *x, *field_form_type, *field_persist;
+
+               options = iks_insert(pubsub, "publish-options");
+               x = iks_insert(options, "x");
+               iks_insert_attrib(x, "xmlns", "jabber:x:data");
+               iks_insert_attrib(x, "type", "submit");
+               field_form_type = iks_insert(x, "field");
+               iks_insert_attrib(field_form_type, "var", "FORM_TYPE");
+               iks_insert_attrib(field_form_type, "type", "hidden");
+               iks_insert_cdata(iks_insert(field_form_type, "value"), "http://jabber.org/protocol/pubsub#publish-options", 0);
+               field_persist = iks_insert(x, "field");
+               iks_insert_attrib(field_persist, "var", "pubsub#persist_items");
+               iks_insert_cdata(iks_insert(field_persist, "value"), "0", 1);
+       }
+
+       return item;
 }
 
 /*!
@@ -3471,11 +3500,11 @@ static iks* aji_build_publish_skeleton(struct aji_client *client, const char *no
  * \return void
  */
 static void aji_publish_device_state(struct aji_client *client, const char *device,
-       const char *device_state)
+                                    const char *device_state, unsigned int cachable)
 {
-       iks *request = aji_build_publish_skeleton(client, device, "device_state");
+       iks *request = aji_build_publish_skeleton(client, device, "device_state", cachable);
        iks *state;
-       char eid_str[20];
+       char eid_str[20], cachable_str[2];
        if (ast_test_flag(&pubsubflags, AJI_PUBSUB_AUTOCREATE)) {
                if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
                        aji_create_pubsub_node(client, "leaf", device, "device_state");
@@ -3487,6 +3516,8 @@ static void aji_publish_device_state(struct aji_client *client, const char *devi
        state = iks_insert(request, "state");
        iks_insert_attrib(state, "xmlns", "http://asterisk.org");
        iks_insert_attrib(state, "eid", eid_str);
+       snprintf(cachable_str, sizeof(cachable_str), "%u", cachable);
+       iks_insert_attrib(state, "cachable", cachable_str);
        iks_insert_cdata(state, device_state, strlen(device_state));
        ast_aji_send(client, iks_root(request));
        iks_delete(request);
@@ -3508,7 +3539,7 @@ static void aji_publish_mwi(struct aji_client *client, const char *mailbox,
        char eid_str[20];
        iks *mailbox_node, *request;
        snprintf(full_mailbox, sizeof(full_mailbox), "%s@%s", mailbox, context);
-       request = aji_build_publish_skeleton(client, full_mailbox, "message_waiting");
+       request = aji_build_publish_skeleton(client, full_mailbox, "message_waiting", 1);
        ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
        mailbox_node = iks_insert(request, "mailbox");
        iks_insert_attrib(mailbox_node, "xmlns", "http://asterisk.org");