Asterisk - The Open Source Telephony Project  18.5.0
stasis_message.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * David M. Lee, II <[email protected]>
7  *
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.
13  *
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.
17  */
18 
19 /*! \file
20  *
21  * \brief Stasis Message API.
22  *
23  * \author David M. Lee, II <[email protected]>
24  */
25 
26 /*** MODULEINFO
27  <support_level>core</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 #include "asterisk/astobj2.h"
33 #include "asterisk/stasis.h"
34 #include "asterisk/utils.h"
35 #include "asterisk/hashtab.h"
36 
37 /*! \internal */
40  char *name;
41  unsigned int hash;
42  int id;
44 };
45 
47 static int message_type_id;
48 
49 static void message_type_dtor(void *obj)
50 {
51  struct stasis_message_type *type = obj;
52  ast_free(type->name);
53  type->name = NULL;
54 }
55 
58  struct stasis_message_type **result)
59 {
60  struct stasis_message_type *type;
61 
62  /* Check for declination */
63  if (name && stasis_message_type_declined(name)) {
65  }
66 
67  type = ao2_t_alloc_options(sizeof(*type), message_type_dtor,
68  AO2_ALLOC_OPT_LOCK_NOLOCK, name ?: "");
69  if (!type) {
71  }
72  if (!vtable) {
73  /* Null object pattern, FTW! */
74  vtable = &null_vtable;
75  }
76 
77  type->name = ast_strdup(name);
78  if (!type->name) {
79  ao2_cleanup(type);
81  }
82  type->hash = ast_hashtab_hash_string(name);
83  type->vtable = vtable;
84  if (vtable->to_json) {
86  }
87  if (vtable->to_ami) {
89  }
90  if (vtable->to_event) {
92  }
94  *result = type;
95 
97 }
98 
100 {
101  return type->name;
102 }
103 
105 {
106  return type->hash;
107 }
108 
110 {
111  return type->id;
112 }
113 
115  const struct stasis_message_type *type)
116 {
117  return type->available_formatters;
118 }
119 
120 /*! \internal */
122  /*! Time the message was created */
123  struct timeval timestamp;
124  /*! Type of the message */
126  /*! Where this message originated. NULL if aggregate message. */
127  const struct ast_eid *eid_ptr;
128  /*! Message content */
129  void *data;
130  /*! Where this message originated. */
131  struct ast_eid eid;
132 };
133 
134 static void stasis_message_dtor(void *obj)
135 {
136  struct stasis_message *message = obj;
137  ao2_cleanup(message->data);
138 }
139 
141 {
142  struct stasis_message *message;
143 
144  if (type == NULL || data == NULL) {
145  return NULL;
146  }
147 
148  message = ao2_t_alloc_options(sizeof(*message), stasis_message_dtor,
150  if (message == NULL) {
151  return NULL;
152  }
153 
154  message->timestamp = ast_tvnow();
155  /*
156  * XXX Normal ao2 ref counting rules says we should increment the message
157  * type ref here and decrement it in stasis_message_dtor(). However, the
158  * stasis message could be cached and legitimately cause the type ref count
159  * to hit the excessive ref count assertion. Since the message type
160  * practically has to be a global object anyway, we can get away with not
161  * holding a ref in the stasis message.
162  */
163  message->type = type;
164  ao2_ref(data, +1);
165  message->data = data;
166  if (eid) {
167  message->eid_ptr = &message->eid;
168  message->eid = *eid;
169  }
170 
171  return message;
172 }
173 
175 {
176  return stasis_message_create_full(type, data, &ast_eid_default);
177 }
178 
179 const struct ast_eid *stasis_message_eid(const struct stasis_message *msg)
180 {
181  if (msg == NULL) {
182  return NULL;
183  }
184  return msg->eid_ptr;
185 }
186 
188 {
189  if (msg == NULL) {
190  return NULL;
191  }
192  return msg->type;
193 }
194 
195 void *stasis_message_data(const struct stasis_message *msg)
196 {
197  if (msg == NULL) {
198  return NULL;
199  }
200  return msg->data;
201 }
202 
203 const struct timeval *stasis_message_timestamp(const struct stasis_message *msg)
204 {
205  if (msg == NULL) {
206  return NULL;
207  }
208  return &msg->timestamp;
209 }
210 
211 #define INVOKE_VIRTUAL(fn, ...) \
212  ({ \
213  if (!msg) { \
214  return NULL; \
215  } \
216  ast_assert(msg->type != NULL); \
217  ast_assert(msg->type->vtable != NULL); \
218  if (!msg->type->vtable->fn) { \
219  return NULL; \
220  } \
221  msg->type->vtable->fn(__VA_ARGS__); \
222  })
223 
225 {
226  return INVOKE_VIRTUAL(to_ami, msg);
227 }
228 
230  struct stasis_message *msg,
231  struct stasis_message_sanitizer *sanitize)
232 {
233  return INVOKE_VIRTUAL(to_json, msg, sanitize);
234 }
235 
237 {
238  return INVOKE_VIRTUAL(to_event, msg);
239 }
240 
241 #define HAS_VIRTUAL(fn, msg) \
242  ({ \
243  if (!msg) { \
244  return 0; \
245  } \
246  ast_assert(msg->type != NULL); \
247  ast_assert(msg->type->vtable != NULL); \
248  !!msg->type->vtable->fn; \
249  })
250 
252 {
253  return HAS_VIRTUAL(to_ami, msg);
254 }
static const char type[]
Definition: chan_ooh323.c:109
Struct containing info for an AMI event to send out.
Definition: manager.h:491
An event.
Definition: event.c:81
int stasis_message_type_declined(const char *name)
Check whether a message type is declined.
Definition: stasis.c:2283
Asterisk main include file. File version handling, generic pbx functions.
static int message_type_id
Virtual table providing methods for messages.
Definition: stasis.h:239
struct ast_eid eid
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
Generic (perhaps overly so) hashtable implementation Hash Table support in Asterisk.
static void stasis_message_dtor(void *obj)
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define ao2_t_alloc_options(data_size, destructor_fn, options, debug_msg)
Allocate and initialize an object.
Definition: astobj2.h:404
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
struct ast_event *(* to_event)(struct stasis_message *message)
Build the ast_event representation of the message.
Definition: stasis.h:281
const struct ast_eid * stasis_message_eid(const struct stasis_message *msg)
Get the entity id for a stasis_message.
struct ast_manager_event_blob * stasis_message_to_ami(struct stasis_message *msg)
Build the AMI representation of the message.
An Entity ID is essentially a MAC address, brief and unique.
Definition: utils.h:786
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:755
Structure containing callbacks for Stasis message sanitization.
Definition: stasis.h:200
Utility functions.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message_type * type
struct ast_json *(* to_json)(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
Build the JSON representation of the message.
Definition: stasis.h:253
#define INVOKE_VIRTUAL(fn,...)
struct timeval timestamp
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const char * stasis_message_type_name(const struct stasis_message_type *type)
Gets the name of a given message type.
static struct stasis_message_vtable null_vtable
int stasis_message_can_be_ami(struct stasis_message *msg)
Determine if the given message can be converted to AMI.
struct stasis_message * stasis_message_create_full(struct stasis_message_type *type, void *data, const struct ast_eid *eid)
Create a new message for an entity.
unsigned char eid[6]
Definition: utils.h:787
enum stasis_subscription_message_formatters stasis_message_type_available_formatters(const struct stasis_message_type *type)
Get a bitmap of available formatters for a message type.
struct ast_json * stasis_message_to_json(struct stasis_message *msg, struct stasis_message_sanitizer *sanitize)
Build the JSON representation of the message.
static void message_type_dtor(void *obj)
struct ast_manager_event_blob *(* to_ami)(struct stasis_message *message)
Build the AMI representation of the message.
Definition: stasis.h:266
#define ast_free(a)
Definition: astmm.h:182
static void to_ami(struct ast_sip_subscription *sub, struct ast_str **buf)
unsigned int ast_hashtab_hash_string(const void *obj)
Hashes a string to a number.
Definition: hashtab.c:153
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
struct stasis_message_vtable * vtable
struct ast_eid ast_eid_default
Global EID.
Definition: options.c:93
const struct timeval * stasis_message_timestamp(const struct stasis_message *msg)
Get the time when a message was created.
#define HAS_VIRTUAL(fn, msg)
unsigned int stasis_message_type_hash(const struct stasis_message_type *type)
Gets the hash of a given message type.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static PGresult * result
Definition: cel_pgsql.c:88
enum stasis_subscription_message_formatters available_formatters
Abstract JSON element (object, array, string, int, ...).
const struct ast_eid * eid_ptr
int stasis_message_type_id(const struct stasis_message_type *type)
Gets the id of a given message type.
stasis_subscription_message_formatters
Stasis subscription formatter filters.
Definition: stasis.h:311
int stasis_message_type_create(const char *name, struct stasis_message_vtable *vtable, struct stasis_message_type **result)
Create a new message type.
struct ast_event * stasis_message_to_event(struct stasis_message *msg)
Build the Generic event system representation of the message.