]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Prevent exhaustion of system resources through exploitation of event cache
authorMatthew Jordan <mjordan@digium.com>
Wed, 2 Jan 2013 18:22:39 +0000 (18:22 +0000)
committerMatthew Jordan <mjordan@digium.com>
Wed, 2 Jan 2013 18:22:39 +0000 (18:22 +0000)
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

git-svn-id: https://origsvn.digium.com/svn/asterisk/certified/branches/1.8.15@378333 65c4cc65-6c06-0410-ace0-fbb531ad65f3

18 files changed:
apps/app_confbridge.c
apps/app_meetme.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/channel.c
main/devicestate.c
main/event.c
main/features.c
res/res_calendar.c
res/res_jabber.c

index ddde4331686544818271f9601d35b2f456660760..b3736b969fbdb7a14ec925d3ccf5e62d710a1f90 100644 (file)
@@ -487,7 +487,7 @@ static struct conference_bridge *join_conference_bridge(const char *name, struct
 
        /* Set the device state for this conference */
        if (conference_bridge->users == 1) {
-               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);
        }
 
        /* If the caller is a marked user or is waiting for a marked user to enter pass 'em off, otherwise pass them off to do regular joining stuff */
@@ -569,7 +569,7 @@ static void  leave_conference_bridge(struct conference_bridge *conference_bridge
                }
        } else {
                /* Set device state to "not in use" */
-               ast_devstate_changed(AST_DEVICE_NOT_INUSE, "confbridge:%s", conference_bridge->name);
+               ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "confbridge:%s", conference_bridge->name);
 
                ao2_unlink(conference_bridges, conference_bridge);
        }
index 0b85c135743ca74c18c4dfca78d60d5213d92cfd..77db47bfc942b0e94577a6c4bb71994d7ef07d63 100644 (file)
@@ -2496,7 +2496,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);
 
@@ -3799,7 +3799,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);
                }
 
                /* Return the number of seconds the user was in the conf */
@@ -5219,8 +5219,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;
                }
        }
@@ -5718,8 +5718,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);
 
@@ -6228,8 +6228,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 eba07c8ad516558d5934fa9da47e3caffa567c7e..4dc9bc0f0f1074e4ddf85ea39a1b8fd637691a3b 100644 (file)
@@ -618,7 +618,7 @@ static struct ast_frame *agent_read(struct ast_channel *ast)
                if (p->chan) {
                        p->chan->_bridge = 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, 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) {
@@ -994,7 +994,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) {
@@ -2134,7 +2134,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) {
@@ -2155,7 +2155,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 {
@@ -2215,7 +2215,7 @@ static int login_exec(struct ast_channel *chan, const char *data)
                                                ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, 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 c3d912329414f7ad08f54999c9b36f648b038318..a928c498880eee81a36877aafd54a7736167d2b2 100644 (file)
@@ -3312,7 +3312,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. */
@@ -3328,7 +3328,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) */
 }
@@ -9788,7 +9788,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);
+       tmp->flags |= 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 767866380d64471063e2ec15796ae7c23029766c..169d262dd39b0d0c0cdaff828017cb7c372ea151 100644 (file)
@@ -5731,7 +5731,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, format_t capability, const char *linkedid)
+static struct ast_channel *ast_iax2_new(int callno, int state, format_t capability, const char *linkedid, unsigned int cachable)
 {
        struct ast_channel *tmp;
        struct chan_iax2_pvt *i;
@@ -5800,6 +5800,10 @@ static struct ast_channel *ast_iax2_new(int callno, int state, format_t capabili
        i->owner = tmp;
        i->capability = capability;
 
+       if (!cachable) {
+               tmp->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE;
+       }
+
        /* Set inherited variables */
        if (i->vars) {
                for (v = i->vars ; v ; v = v->next)
@@ -8088,7 +8092,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;
@@ -8642,7 +8646,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);
 
@@ -8697,7 +8701,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) {
@@ -8774,14 +8778,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\n", p->name);
                        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 */
@@ -10292,7 +10296,8 @@ static int socket_process(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;
@@ -10925,13 +10930,13 @@ static int socket_process(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;
@@ -11173,7 +11178,7 @@ static int socket_process(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;
@@ -11244,7 +11249,7 @@ immediatedial:
                                                        ast_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;
@@ -11997,7 +12002,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]);
@@ -12165,7 +12170,7 @@ static struct ast_channel *iax2_request(const char *type, format_t format, const
        if (cai.found)
                ast_string_field_set(iaxs[callno], host, pds.peer);
 
-       c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability, requestor ? requestor->linkedid : NULL);
+       c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability, requestor ? requestor->linkedid : NULL, cai.found);
 
        ast_mutex_unlock(&iaxsl[callno]);
 
index b82b9d28e96db043226979f5e377be1bfdd6905e..24a0eaa431efb2758566c017fd5fa8e00639e094 100644 (file)
@@ -1196,6 +1196,9 @@ static struct ast_channel *local_new(struct local_pvt *p, int state, const char
        tmp->tech_pvt = p;
        tmp2->tech_pvt = p;
 
+       tmp->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE;
+       tmp2->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE;
+
        p->owner = tmp;
        p->chan = tmp2;
        p->u_owner = ast_module_user_add(p->owner);
index 3b2359bfd5c774232d8a8131e0055876a6a7131a..12a0905388c1e390741e79bc004df8dcdbd47d4b 100644 (file)
@@ -6115,7 +6115,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);
                unref_peer(p, "update_call_counter: unref_peer from call counter");
        }
        return 0;
@@ -7359,6 +7359,9 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
        if (i->rtp)
                ast_jb_configure(tmp, &global_jbconf);
 
+       if (!i->relatedpeer) {
+               tmp->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE;
+       }
        /* Set channel variables for this call from configuration */
        for (v = i->chanvars ; v ; v = v->next) {
                char valuebuf[1024];
@@ -14006,7 +14009,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
@@ -14788,8 +14791,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, (p->owner->flags & AST_FLAG_DISABLE_DEVSTATE_CACHE ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE),
+                            "SIP/%s", p->relatedpeer->name);
+
        return;
 }
 
@@ -15226,7 +15230,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) {
@@ -21356,7 +21360,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);
                }
@@ -26947,7 +26951,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 5d965157cc830ea2b3e8dade1619af118a33b364..cd2f62a144190ff6971a206a157a23598d6b2c94 100644 (file)
@@ -1926,7 +1926,7 @@ static int skinny_register(struct skinny_req *req, struct skinnysession *s)
                                        register_exten(l);
                                        /* initialize MWI on line and device */
                                        mwi_event_cb(0, l);
-                                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name);
+                                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
                                }
                                --instance;
                        }
@@ -1964,7 +1964,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@%s", l->name, d->name);
+                               ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
                        }
                }
        }
@@ -5328,7 +5328,7 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
                        ast_verb(1, "RECEIVED UNKNOWN STIMULUS:  %d(%d/%d)\n", event, instance, callreference);
                break;
        }
-       ast_devstate_changed(AST_DEVICE_UNKNOWN, "Skinny/%s@%s", l->name, d->name);
+       ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
 
        return 1;
 }
@@ -5379,7 +5379,7 @@ static int handle_offhook_message(struct skinny_req *req, struct skinnysession *
        transmit_ringer_mode(d, SKINNY_RING_OFF);
        l->hookstate = SKINNY_OFFHOOK;
 
-       ast_devstate_changed(AST_DEVICE_INUSE, "Skinny/%s@%s", l->name, d->name);
+       ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
 
        if (sub && sub->onhold) {
                return 1;
@@ -5455,7 +5455,7 @@ static int handle_onhook_message(struct skinny_req *req, struct skinnysession *s
                return 0;
        }
 
-       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name);
+       ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
 
        if (sub->onhold) {
                return 0;
@@ -5841,7 +5841,7 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
                return 0;
        }
 
-       ast_devstate_changed(AST_DEVICE_INUSE, "Skinny/%s@%s", l->name, d->name);
+       ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
 
        switch(event) {
        case SOFTKEY_NONE:
@@ -6056,7 +6056,7 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
                                transmit_callstate(d, l->instance, sub->callid, l->hookstate);
                        }
 
-                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name);
+                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
                        if (skinnydebug)
                                ast_verb(1, "Skinny %s@%s went on hook\n", l->name, d->name);
                        if (l->transfer && sub->xferor && sub->owner->_state >= AST_STATE_RING) {
@@ -6080,7 +6080,7 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
                                }
                        }
                        if ((l->hookstate == SKINNY_ONHOOK) && (AST_LIST_NEXT(sub, list) && !AST_LIST_NEXT(sub, list)->rtp)) {
-                               ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name);
+                               ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
                        }
                }
                break;
index e1f34387a116f8d87d2217a5d67edc271a3175dc..6472610c8a70a0b2bfdd5451af2ada658f052d9e 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 afe7d9beec8a4c23f08b8706a99ac31e54845025..cd59843abd4cc8d5e456f69860d6dd895b24e1f6 100644 (file)
@@ -936,6 +936,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 66ca2bd1a3ecddb1fd4d0ac44741cc1aa26e43dd..86740bc2fd69b735906d1e9d71adcd4798924d66 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 9401961a74d953e01c6f84957ee7a2e1f89dc703..84a2b2850638e038dcdfaad3a79cbd92f43f4441 100644 (file)
@@ -290,8 +290,14 @@ enum ast_event_ie_type {
        AST_EVENT_IE_PRESENCE_STATE      = 0x0036,
        AST_EVENT_IE_PRESENCE_SUBTYPE    = 0x0037,
        AST_EVENT_IE_PRESENCE_MESSAGE    = 0x0038,
+       /*!
+        * \brief Event non-cachability flag
+        * Used by: All events
+        * Payload type: UINT
+        */
+       AST_EVENT_IE_CACHABLE            = 0x0039,
        /*! \brief Must be the last IE value +1 */
-       AST_EVENT_IE_TOTAL               = 0x0039,
+       AST_EVENT_IE_TOTAL               = 0x003a,
 };
 
 /*!
index 7be65607031ba9bfc44e469795b0b8c5bc8d73b7..222fb1bdc3e7cd9939c2a72b8eef11cea9d029bc 100644 (file)
@@ -290,6 +290,7 @@ static void channel_data_add_flags(struct ast_data *tree,
        ast_data_add_bool(tree, "BRIDGE_HANGUP_RUN", ast_test_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN));
        ast_data_add_bool(tree, "BRIDGE_HANGUP_DONT", ast_test_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT));
        ast_data_add_bool(tree, "DISABLE_WORKAROUNDS", ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS));
+       ast_data_add_bool(tree, "DISABLE_DEVSTATE_CACHE", ast_test_flag(chan, AST_FLAG_DISABLE_DEVSTATE_CACHE));
 }
 
 #if defined(KEEP_TILL_CHANNEL_PARTY_NUMBER_INFO_NEEDED)
@@ -2488,7 +2489,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, (chan->flags & AST_FLAG_DISABLE_DEVSTATE_CACHE ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), device_name);
        }
        ast_atomic_fetchadd_int(&chancount, -1);
 }
@@ -6970,7 +6971,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, (chan->flags & AST_FLAG_DISABLE_DEVSTATE_CACHE ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), name);
 
        /* setstate used to conditionally report Newchannel; this is no more */
        ast_manager_event(chan, EVENT_FLAG_CALL, "Newstate",
index 84eedc81c5d0b7f830a46ab09ac255b69b4222f2..aabf806e749b67c34c83e5e2b79ea5e23b1868b3 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 f499ac7c6ab9eadebceb4f1c0b2ff2807e49f2e0..39bf4cb44696dc5ffb6a6b552d57a07a7745dbe3 100644 (file)
@@ -274,6 +274,7 @@ static const struct ie_map {
        [AST_EVENT_IE_CHALLENGE]           = { AST_EVENT_IE_PLTYPE_STR,  "Challenge" },
        [AST_EVENT_IE_RESPONSE]            = { AST_EVENT_IE_PLTYPE_STR,  "Response" },
        [AST_EVENT_IE_EXPECTED_RESPONSE]   = { AST_EVENT_IE_PLTYPE_STR,  "ExpectedResponse" },
+       [AST_EVENT_IE_CACHABLE]            = { AST_EVENT_IE_PLTYPE_UINT,  "Cachable" },
 };
 
 const char *ast_event_get_type_name(const struct ast_event *event)
index ba4f9bd16930ee9cca365ff6f7ae9824d4c49ca0..aa5916fea387eb669e9abac26c56ca222c5e5e16 100644 (file)
@@ -1075,7 +1075,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 959c0493f4668e543f13d27efa2c7d85a975e670..7c8518b85ace6ab854e1237b34f92509c2a11e1f 100644 (file)
@@ -575,9 +575,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);
                }
        }
 
@@ -818,9 +818,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 502083fb6f20dedbcf9e4b027f3e90a2f9ecf857..c08643fadc803c14e14e3a87c886eef9d20deedb 100644 (file)
@@ -352,7 +352,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);
@@ -366,7 +366,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);
@@ -3266,6 +3266,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)))
        {
@@ -3277,7 +3278,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);
 }
 
@@ -3317,11 +3319,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");
@@ -3336,11 +3340,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")) {
@@ -3360,7 +3367,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;
 }
 
@@ -3435,7 +3448,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;
@@ -3449,8 +3462,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;
 }
 
 /*!
@@ -3461,11 +3490,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");
@@ -3477,6 +3506,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);
@@ -3496,7 +3527,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");