2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2007 - 2008, Digium, Inc.
6 * Russell Bryant <russell@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Internal generic event system
23 * \author Russell Bryant <russell@digium.com>
27 <support_level>core</support_level>
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34 #include "asterisk/_private.h"
36 #include "asterisk/event.h"
37 #include "asterisk/linkedlists.h"
38 #include "asterisk/dlinkedlists.h"
39 #include "asterisk/lock.h"
40 #include "asterisk/utils.h"
41 #include "asterisk/unaligned.h"
42 #include "asterisk/utils.h"
43 #include "asterisk/taskprocessor.h"
44 #include "asterisk/astobj2.h"
45 #include "asterisk/cli.h"
48 * \brief An event information element
50 * \note The format of this structure is important. Since these events may
51 * be sent directly over a network, changing this structure will break
52 * compatibility with older versions. However, at this point, this code
53 * has not made it into a release, so it is still fair game for change.
56 enum ast_event_ie_type ie_type:16;
57 /*! Total length of the IE payload */
58 uint16_t ie_payload_len;
59 unsigned char ie_payload[0];
60 } __attribute__((packed));
63 * \brief The payload for a string information element
65 struct ast_event_ie_str_payload {
66 /*! \brief A hash calculated with ast_str_hash(), to speed up comparisons */
68 /*! \brief The actual string, null terminated */
70 } __attribute__((packed));
75 * An ast_event consists of an event header (this structure), and zero or
76 * more information elements defined by ast_event_ie.
78 * \note The format of this structure is important. Since these events may
79 * be sent directly over a network, changing this structure will break
80 * compatibility with older versions. However, at this point, this code
81 * has not made it into a release, so it is still fair game for change.
85 enum ast_event_type type:16;
86 /*! Total length of the event */
87 uint16_t event_len:16;
88 /*! The data payload of the event, made up of information elements */
89 unsigned char payload[0];
90 } __attribute__((packed));
93 struct ast_event_ie_val {
94 AST_LIST_ENTRY(ast_event_ie_val) entry;
95 enum ast_event_ie_type ie_type;
96 enum ast_event_ie_pltype ie_pltype;
111 static const char * const event_names[AST_EVENT_TOTAL] = {
112 [AST_EVENT_ALL] = "All",
113 [AST_EVENT_CUSTOM] = "Custom",
114 [AST_EVENT_MWI] = "MWI",
115 [AST_EVENT_SUB] = "Subscription",
116 [AST_EVENT_UNSUB] = "Unsubscription",
117 [AST_EVENT_DEVICE_STATE] = "DeviceState",
118 [AST_EVENT_DEVICE_STATE_CHANGE] = "DeviceStateChange",
119 [AST_EVENT_CEL] = "CEL",
120 [AST_EVENT_SECURITY] = "Security",
121 [AST_EVENT_NETWORK_CHANGE] = "NetworkChange",
122 [AST_EVENT_PRESENCE_STATE] = "PresenceState",
123 [AST_EVENT_ACL_CHANGE] = "ACLChange",
124 [AST_EVENT_PING] = "Ping",
128 * \brief IE payload types and names
130 static const struct ie_map {
131 enum ast_event_ie_pltype ie_pltype;
133 } ie_maps[AST_EVENT_IE_TOTAL] = {
134 [AST_EVENT_IE_NEWMSGS] = { AST_EVENT_IE_PLTYPE_UINT, "NewMessages" },
135 [AST_EVENT_IE_OLDMSGS] = { AST_EVENT_IE_PLTYPE_UINT, "OldMessages" },
136 [AST_EVENT_IE_MAILBOX] = { AST_EVENT_IE_PLTYPE_STR, "Mailbox" },
137 [AST_EVENT_IE_UNIQUEID] = { AST_EVENT_IE_PLTYPE_UINT, "UniqueID" },
138 [AST_EVENT_IE_EVENTTYPE] = { AST_EVENT_IE_PLTYPE_UINT, "EventType" },
139 [AST_EVENT_IE_EXISTS] = { AST_EVENT_IE_PLTYPE_UINT, "Exists" },
140 [AST_EVENT_IE_DEVICE] = { AST_EVENT_IE_PLTYPE_STR, "Device" },
141 [AST_EVENT_IE_STATE] = { AST_EVENT_IE_PLTYPE_UINT, "State" },
142 [AST_EVENT_IE_CONTEXT] = { AST_EVENT_IE_PLTYPE_STR, "Context" },
143 [AST_EVENT_IE_EID] = { AST_EVENT_IE_PLTYPE_RAW, "EntityID" },
144 [AST_EVENT_IE_CEL_EVENT_TYPE] = { AST_EVENT_IE_PLTYPE_UINT, "CELEventType" },
145 [AST_EVENT_IE_CEL_EVENT_TIME] = { AST_EVENT_IE_PLTYPE_UINT, "CELEventTime" },
146 [AST_EVENT_IE_CEL_EVENT_TIME_USEC] = { AST_EVENT_IE_PLTYPE_UINT, "CELEventTimeUSec" },
147 [AST_EVENT_IE_CEL_USEREVENT_NAME] = { AST_EVENT_IE_PLTYPE_UINT, "CELUserEventName" },
148 [AST_EVENT_IE_CEL_CIDNAME] = { AST_EVENT_IE_PLTYPE_STR, "CELCIDName" },
149 [AST_EVENT_IE_CEL_CIDNUM] = { AST_EVENT_IE_PLTYPE_STR, "CELCIDNum" },
150 [AST_EVENT_IE_CEL_EXTEN] = { AST_EVENT_IE_PLTYPE_STR, "CELExten" },
151 [AST_EVENT_IE_CEL_CONTEXT] = { AST_EVENT_IE_PLTYPE_STR, "CELContext" },
152 [AST_EVENT_IE_CEL_CHANNAME] = { AST_EVENT_IE_PLTYPE_STR, "CELChanName" },
153 [AST_EVENT_IE_CEL_APPNAME] = { AST_EVENT_IE_PLTYPE_STR, "CELAppName" },
154 [AST_EVENT_IE_CEL_APPDATA] = { AST_EVENT_IE_PLTYPE_STR, "CELAppData" },
155 [AST_EVENT_IE_CEL_AMAFLAGS] = { AST_EVENT_IE_PLTYPE_STR, "CELAMAFlags" },
156 [AST_EVENT_IE_CEL_ACCTCODE] = { AST_EVENT_IE_PLTYPE_UINT, "CELAcctCode" },
157 [AST_EVENT_IE_CEL_UNIQUEID] = { AST_EVENT_IE_PLTYPE_STR, "CELUniqueID" },
158 [AST_EVENT_IE_CEL_USERFIELD] = { AST_EVENT_IE_PLTYPE_STR, "CELUserField" },
159 [AST_EVENT_IE_CEL_CIDANI] = { AST_EVENT_IE_PLTYPE_STR, "CELCIDani" },
160 [AST_EVENT_IE_CEL_CIDRDNIS] = { AST_EVENT_IE_PLTYPE_STR, "CELCIDrdnis" },
161 [AST_EVENT_IE_CEL_CIDDNID] = { AST_EVENT_IE_PLTYPE_STR, "CELCIDdnid" },
162 [AST_EVENT_IE_CEL_PEER] = { AST_EVENT_IE_PLTYPE_STR, "CELPeer" },
163 [AST_EVENT_IE_CEL_LINKEDID] = { AST_EVENT_IE_PLTYPE_STR, "CELLinkedID" },
164 [AST_EVENT_IE_CEL_PEERACCT] = { AST_EVENT_IE_PLTYPE_STR, "CELPeerAcct" },
165 [AST_EVENT_IE_CEL_EXTRA] = { AST_EVENT_IE_PLTYPE_STR, "CELExtra" },
166 [AST_EVENT_IE_SECURITY_EVENT] = { AST_EVENT_IE_PLTYPE_STR, "SecurityEvent" },
167 [AST_EVENT_IE_EVENT_VERSION] = { AST_EVENT_IE_PLTYPE_UINT, "EventVersion" },
168 [AST_EVENT_IE_SERVICE] = { AST_EVENT_IE_PLTYPE_STR, "Service" },
169 [AST_EVENT_IE_MODULE] = { AST_EVENT_IE_PLTYPE_STR, "Module" },
170 [AST_EVENT_IE_ACCOUNT_ID] = { AST_EVENT_IE_PLTYPE_STR, "AccountID" },
171 [AST_EVENT_IE_SESSION_ID] = { AST_EVENT_IE_PLTYPE_STR, "SessionID" },
172 [AST_EVENT_IE_SESSION_TV] = { AST_EVENT_IE_PLTYPE_STR, "SessionTV" },
173 [AST_EVENT_IE_ACL_NAME] = { AST_EVENT_IE_PLTYPE_STR, "ACLName" },
174 [AST_EVENT_IE_LOCAL_ADDR] = { AST_EVENT_IE_PLTYPE_STR, "LocalAddress" },
175 [AST_EVENT_IE_REMOTE_ADDR] = { AST_EVENT_IE_PLTYPE_STR, "RemoteAddress" },
176 [AST_EVENT_IE_EVENT_TV] = { AST_EVENT_IE_PLTYPE_STR, "EventTV" },
177 [AST_EVENT_IE_REQUEST_TYPE] = { AST_EVENT_IE_PLTYPE_STR, "RequestType" },
178 [AST_EVENT_IE_REQUEST_PARAMS] = { AST_EVENT_IE_PLTYPE_STR, "RequestParams" },
179 [AST_EVENT_IE_AUTH_METHOD] = { AST_EVENT_IE_PLTYPE_STR, "AuthMethod" },
180 [AST_EVENT_IE_SEVERITY] = { AST_EVENT_IE_PLTYPE_STR, "Severity" },
181 [AST_EVENT_IE_EXPECTED_ADDR] = { AST_EVENT_IE_PLTYPE_STR, "ExpectedAddress" },
182 [AST_EVENT_IE_CHALLENGE] = { AST_EVENT_IE_PLTYPE_STR, "Challenge" },
183 [AST_EVENT_IE_RESPONSE] = { AST_EVENT_IE_PLTYPE_STR, "Response" },
184 [AST_EVENT_IE_EXPECTED_RESPONSE] = { AST_EVENT_IE_PLTYPE_STR, "ExpectedResponse" },
185 [AST_EVENT_IE_RECEIVED_CHALLENGE] = { AST_EVENT_IE_PLTYPE_STR, "ReceivedChallenge" },
186 [AST_EVENT_IE_RECEIVED_HASH] = { AST_EVENT_IE_PLTYPE_STR, "ReceivedHash" },
187 [AST_EVENT_IE_USING_PASSWORD] = { AST_EVENT_IE_PLTYPE_UINT, "UsingPassword" },
188 [AST_EVENT_IE_ATTEMPTED_TRANSPORT] = { AST_EVENT_IE_PLTYPE_STR, "AttemptedTransport" },
189 [AST_EVENT_IE_CACHABLE] = { AST_EVENT_IE_PLTYPE_UINT, "Cachable" },
190 [AST_EVENT_IE_PRESENCE_PROVIDER] = { AST_EVENT_IE_PLTYPE_STR, "PresenceProvider" },
191 [AST_EVENT_IE_PRESENCE_STATE] = { AST_EVENT_IE_PLTYPE_UINT, "PresenceState" },
192 [AST_EVENT_IE_PRESENCE_SUBTYPE] = { AST_EVENT_IE_PLTYPE_STR, "PresenceSubtype" },
193 [AST_EVENT_IE_PRESENCE_MESSAGE] = { AST_EVENT_IE_PLTYPE_STR, "PresenceMessage" },
196 const char *ast_event_get_type_name(const struct ast_event *event)
198 enum ast_event_type type;
200 type = ast_event_get_type(event);
202 if (type < 0 || type >= ARRAY_LEN(event_names)) {
203 ast_log(LOG_ERROR, "Invalid event type - '%d'\n", type);
207 return event_names[type];
210 const char *ast_event_get_ie_type_name(enum ast_event_ie_type ie_type)
212 if (ie_type <= 0 || ie_type >= ARRAY_LEN(ie_maps)) {
213 ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type);
217 return ie_maps[ie_type].name;
220 enum ast_event_ie_pltype ast_event_get_ie_pltype(enum ast_event_ie_type ie_type)
222 if (ie_type <= 0 || ie_type >= ARRAY_LEN(ie_maps)) {
223 ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type);
224 return AST_EVENT_IE_PLTYPE_UNKNOWN;
227 return ie_maps[ie_type].ie_pltype;
230 size_t ast_event_get_size(const struct ast_event *event)
234 res = ntohs(event->event_len);
239 /*! \brief Subscription event check list. */
240 struct ast_ev_check_list {
241 AST_LIST_HEAD_NOLOCK(, ast_event_ie_val) ie_vals;
244 int ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event)
248 iterator->event_len = ast_event_get_size(event);
249 iterator->event = event;
250 if (iterator->event_len >= sizeof(*event) + sizeof(struct ast_event_ie)) {
251 iterator->ie = (struct ast_event_ie *) ( ((char *) event) + sizeof(*event) );
260 int ast_event_iterator_next(struct ast_event_iterator *iterator)
262 iterator->ie = (struct ast_event_ie *) ( ((char *) iterator->ie) + sizeof(*iterator->ie) + ntohs(iterator->ie->ie_payload_len));
263 return ((iterator->event_len <= (((char *) iterator->ie) - ((char *) iterator->event))) ? -1 : 0);
266 enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator)
268 return ntohs(iterator->ie->ie_type);
271 uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator)
273 return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
276 const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
278 const struct ast_event_ie_str_payload *str_payload;
280 str_payload = (struct ast_event_ie_str_payload *) iterator->ie->ie_payload;
282 return str_payload ? str_payload->str : NULL;
285 static void *event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
287 return iterator->ie->ie_payload;
290 enum ast_event_type ast_event_get_type(const struct ast_event *event)
292 return ntohs(event->type);
295 uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
297 const uint32_t *ie_val;
299 ie_val = ast_event_get_ie_raw(event, ie_type);
301 return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
304 const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
306 const struct ast_event_ie_str_payload *str_payload;
308 str_payload = ast_event_get_ie_raw(event, ie_type);
310 return str_payload ? str_payload->str : NULL;
313 const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type)
315 struct ast_event_iterator iterator;
318 for (res = ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
319 if (ast_event_iterator_get_ie_type(&iterator) == ie_type) {
320 return event_iterator_get_ie_raw(&iterator);
327 static uint16_t event_iterator_get_ie_raw_payload_len(struct ast_event_iterator *iterator)
329 return ntohs(iterator->ie->ie_payload_len);
332 uint16_t ast_event_get_ie_raw_payload_len(const struct ast_event *event, enum ast_event_ie_type ie_type)
334 struct ast_event_iterator iterator;
337 for (res = ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
338 if (ast_event_iterator_get_ie_type(&iterator) == ie_type) {
339 return event_iterator_get_ie_raw_payload_len(&iterator);
347 int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
350 struct ast_event_ie_str_payload *str_payload;
353 payload_len = sizeof(*str_payload) + strlen(str);
354 str_payload = ast_alloca(payload_len);
356 strcpy(str_payload->str, str);
357 str_payload->hash = ast_str_hash(str);
359 return ast_event_append_ie_raw(event, ie_type, str_payload, payload_len);
362 int ast_event_append_ie_uint(struct ast_event **event, enum ast_event_ie_type ie_type,
366 return ast_event_append_ie_raw(event, ie_type, &data, sizeof(data));
369 int ast_event_append_ie_bitflags(struct ast_event **event, enum ast_event_ie_type ie_type,
372 flags = htonl(flags);
373 return ast_event_append_ie_raw(event, ie_type, &flags, sizeof(flags));
376 int ast_event_append_ie_raw(struct ast_event **event, enum ast_event_ie_type ie_type,
377 const void *data, size_t data_len)
379 struct ast_event_ie *ie;
380 struct ast_event *old_event;
381 unsigned int extra_len;
384 event_len = ntohs((*event)->event_len);
385 extra_len = sizeof(*ie) + data_len;
388 *event = ast_realloc(*event, event_len + extra_len);
394 ie = (struct ast_event_ie *) ( ((char *) *event) + event_len );
395 ie->ie_type = htons(ie_type);
396 ie->ie_payload_len = htons(data_len);
397 memcpy(ie->ie_payload, data, data_len);
399 (*event)->event_len = htons(event_len + extra_len);
404 struct ast_event *ast_event_new(enum ast_event_type type, ...)
407 struct ast_event *event;
408 enum ast_event_ie_type ie_type;
409 struct ast_event_ie_val *ie_val;
410 AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
413 if (type >= AST_EVENT_TOTAL) {
414 ast_log(LOG_WARNING, "Someone tried to create an event of invalid "
415 "type '%u'!\n", type);
420 for (ie_type = va_arg(ap, enum ast_event_ie_type);
421 ie_type != AST_EVENT_IE_END;
422 ie_type = va_arg(ap, enum ast_event_ie_type))
424 struct ast_event_ie_val *ie_value = ast_alloca(sizeof(*ie_value));
427 memset(ie_value, 0, sizeof(*ie_value));
428 ie_value->ie_type = ie_type;
429 ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
431 switch (ie_value->ie_pltype) {
432 case AST_EVENT_IE_PLTYPE_UINT:
433 ie_value->payload.uint = va_arg(ap, uint32_t);
436 case AST_EVENT_IE_PLTYPE_BITFLAGS:
437 ie_value->payload.uint = va_arg(ap, uint32_t);
440 case AST_EVENT_IE_PLTYPE_STR:
441 ie_value->payload.str = va_arg(ap, const char *);
444 case AST_EVENT_IE_PLTYPE_RAW:
446 void *data = va_arg(ap, void *);
447 size_t datalen = va_arg(ap, size_t);
448 ie_value->payload.raw = ast_alloca(datalen);
449 memcpy(ie_value->payload.raw, data, datalen);
450 ie_value->raw_datalen = datalen;
454 case AST_EVENT_IE_PLTYPE_UNKNOWN:
455 case AST_EVENT_IE_PLTYPE_EXISTS:
460 AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
462 ast_log(LOG_WARNING, "Unsupported PLTYPE(%d)\n", ie_value->ie_pltype);
467 if (!(event = ast_calloc(1, sizeof(*event)))) {
471 event->type = htons(type);
472 event->event_len = htons(sizeof(*event));
474 AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
475 switch (ie_val->ie_pltype) {
476 case AST_EVENT_IE_PLTYPE_STR:
477 ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
479 case AST_EVENT_IE_PLTYPE_UINT:
480 ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
482 case AST_EVENT_IE_PLTYPE_BITFLAGS:
483 ast_event_append_ie_bitflags(&event, ie_val->ie_type, ie_val->payload.uint);
485 case AST_EVENT_IE_PLTYPE_RAW:
486 ast_event_append_ie_raw(&event, ie_val->ie_type,
487 ie_val->payload.raw, ie_val->raw_datalen);
489 case AST_EVENT_IE_PLTYPE_EXISTS:
490 case AST_EVENT_IE_PLTYPE_UNKNOWN:
494 /* realloc inside one of the append functions failed */
500 if (!ast_event_get_ie_raw(event, AST_EVENT_IE_EID)) {
501 /* If the event is originating on this server, add the server's
502 * entity ID to the event. */
503 ast_event_append_eid(&event);
509 int ast_event_append_eid(struct ast_event **event)
511 return ast_event_append_ie_raw(event, AST_EVENT_IE_EID,
512 &ast_eid_default, sizeof(ast_eid_default));
515 void ast_event_destroy(struct ast_event *event)
520 size_t ast_event_minimum_length(void)
522 return sizeof(struct ast_event);