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)



git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.8@378303 65c4cc65-6c06-0410-ace0-fbb531ad65f3
changes/98/198/1
Matthew Jordan 12 years ago
parent a73c5b80ff
commit 5996dd6a23

@ -486,7 +486,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 */
@ -568,7 +568,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);
}

@ -2576,7 +2576,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);
@ -3884,7 +3884,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 */
@ -5303,8 +5303,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;
}
}
@ -5802,8 +5802,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);
@ -6312,8 +6312,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;

@ -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) {
@ -2138,7 +2138,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) {
@ -2159,7 +2159,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 {
@ -2219,7 +2219,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);

@ -3364,7 +3364,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. */
@ -3380,7 +3380,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) */
}
@ -9804,7 +9804,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);

@ -5729,7 +5729,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;
@ -5798,6 +5798,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)
@ -8084,7 +8088,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;
@ -8638,7 +8642,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);
@ -8693,7 +8697,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) {
@ -8770,14 +8774,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 */
@ -10291,7 +10295,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;
@ -10924,13 +10929,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;
@ -11172,7 +11177,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;
@ -11243,7 +11248,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;
@ -11996,7 +12001,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]);
@ -12164,7 +12169,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]);

@ -1229,6 +1229,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;

@ -6418,7 +6418,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;
@ -7609,6 +7609,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];
@ -14221,7 +14224,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
@ -15003,8 +15006,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;
}
@ -15422,7 +15426,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) {
@ -21414,7 +21418,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);
}
@ -26870,7 +26874,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 */

@ -1925,7 +1925,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;
}
@ -1963,7 +1963,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);
}
}
}
@ -5321,7 +5321,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;
}
@ -5372,7 +5372,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;
@ -5448,7 +5448,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;
@ -5834,7 +5834,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:
@ -6049,7 +6049,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) {
@ -6073,7 +6073,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;

@ -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;

@ -938,6 +938,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 */

@ -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.

@ -283,8 +283,14 @@ enum ast_event_ie_type {
AST_EVENT_IE_CHALLENGE = 0x0032,
AST_EVENT_IE_RESPONSE = 0x0033,
AST_EVENT_IE_EXPECTED_RESPONSE = 0x0034,
/*!
* \brief Event non-cachability flag
* Used by: All events
* Payload type: UINT
*/
AST_EVENT_IE_CACHABLE = 0x0035,
/*! \brief Must be the last IE value +1 */
AST_EVENT_IE_TOTAL = 0x0035,
AST_EVENT_IE_TOTAL = 0x0036,
};
/*!

@ -299,6 +299,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)
@ -2519,7 +2520,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);
}
@ -7058,7 +7059,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",

@ -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);

@ -268,6 +268,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)

@ -1094,7 +1094,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 */

@ -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);

@ -349,7 +349,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);
@ -363,7 +363,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);
@ -3207,6 +3207,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)))
{
@ -3218,7 +3219,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);
}
@ -3258,11 +3260,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");
@ -3277,11 +3281,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")) {
@ -3301,7 +3308,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;
}
@ -3376,7 +3389,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;
@ -3390,8 +3403,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;
}
/*!
@ -3402,11 +3431,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");
@ -3418,6 +3447,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);
@ -3437,7 +3468,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");

Loading…
Cancel
Save