[asterisk-commits] twilson: branch russell/messaging r315987 - in /team/russell/messaging: chann...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Apr 27 15:22:00 CDT 2011
Author: twilson
Date: Wed Apr 27 15:21:55 2011
New Revision: 315987
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=315987
Log:
Add MESSAGE_DATA function for handling custom headers
Modified:
team/russell/messaging/channels/chan_sip.c
team/russell/messaging/doc/asterisk-messaging.txt
team/russell/messaging/include/asterisk/message.h
team/russell/messaging/main/message.c
Modified: team/russell/messaging/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/russell/messaging/channels/chan_sip.c?view=diff&rev=315987&r1=315986&r2=315987
==============================================================================
--- team/russell/messaging/channels/chan_sip.c (original)
+++ team/russell/messaging/channels/chan_sip.c Wed Apr 27 15:21:55 2011
@@ -1253,6 +1253,7 @@
static int transmit_info_with_digit(struct sip_pvt *p, const char digit, unsigned int duration);
static int transmit_info_with_vidupdate(struct sip_pvt *p);
static int transmit_message_with_text(struct sip_pvt *p, const char *text, int init, int auth);
+static int transmit_message_with_msg(struct sip_pvt *p, const struct ast_msg *msg);
static int transmit_refer(struct sip_pvt *p, const char *dest);
static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs, const char *vmexten);
static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message, int terminate);
@@ -13013,6 +13014,29 @@
return res;
}
+/*! \brief Transmit text with SIP MESSAGE method based on an ast_msg */
+static int transmit_message_with_msg(struct sip_pvt *p, const struct ast_msg *msg)
+{
+ struct sip_request req;
+ struct ast_msg_var_iterator *i;
+ const char *var, *val;
+
+ initreqprep(&req, p, SIP_MESSAGE, NULL);
+ ast_string_field_set(p, msg_body, ast_msg_get_body(msg));
+ initialize_initreq(p, &req);
+
+ i = ast_msg_var_iterator_init(msg);
+ while (ast_msg_var_iterator_next(msg, i, &var, &val)) {
+ add_header(&req, var, val);
+ ast_msg_var_unref_current(i);
+ }
+ ast_msg_var_iterator_destroy(i);
+
+ add_text(&req, ast_msg_get_body(msg));
+
+ return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
+}
+
/*! \brief Transmit text with SIP MESSAGE method */
static int transmit_message_with_text(struct sip_pvt *p, const char *text, int init, int auth)
{
@@ -15820,6 +15844,24 @@
return res < 0 ? -1 : 0;
}
+static void set_message_vars_from_req(struct ast_msg *msg, struct sip_request *req)
+{
+ size_t x;
+ char name_buf[1024] = "";
+ char val_buf[1024] = "";
+ char *c;
+
+ for (x = 0; x < req->headers; x++) {
+ const char *header = REQ_OFFSET_TO_STR(req, header[x]);
+ if ((c = strchr(header, ':'))) {
+ ast_copy_string(name_buf, header, MIN((c - header + 1), sizeof(name_buf)));
+ ast_copy_string(val_buf, ast_skip_blanks(c + 1), sizeof(val_buf));
+ ast_trim_blanks(name_buf);
+ ast_msg_set_var(msg, name_buf, val_buf);
+ }
+ }
+}
+
AST_THREADSTORAGE(sip_msg_buf);
/*! \brief Receive SIP MESSAGE method messages
@@ -15939,6 +15981,7 @@
if (res) {
ast_msg_destroy(msg);
} else {
+ set_message_vars_from_req(msg, req);
ast_msg_queue(msg);
}
@@ -23402,7 +23445,7 @@
/* XXX Does pvt->expiry need to be set? */
- res = transmit_message_with_text(pvt, ast_msg_get_body(msg), 1, 0);
+ res = transmit_message_with_msg(pvt, msg);
sip_pvt_unlock(pvt);
sip_scheddestroy(pvt, DEFAULT_TRANS_TIMEOUT);
Modified: team/russell/messaging/doc/asterisk-messaging.txt
URL: http://svnview.digium.com/svn/asterisk/team/russell/messaging/doc/asterisk-messaging.txt?view=diff&rev=315987&r1=315986&r2=315987
==============================================================================
--- team/russell/messaging/doc/asterisk-messaging.txt (original)
+++ team/russell/messaging/doc/asterisk-messaging.txt Wed Apr 27 15:21:55 2011
@@ -26,8 +26,9 @@
1.1) Scope
2) The Asterisk Dialplan
2.1) MESSAGE() Function
- 2.2) MessageSend() Application
- 2.3) Dialplan Examples
+ 2.2) MESSAGE_DATA() Function
+ 2.3) MessageSend() Application
+ 2.4) Dialplan Examples
3) Implementation Notes
3.1) Channels and Threads
3.2) Message Protocols
@@ -112,7 +113,26 @@
will always be UTF-8.
---- 2.2) MessageSend() Application
+--- 2.2) MESSAGE_DATA() Function
+
+ It is useful to be able to add or pass through custom signaling data to an
+outbound message. The MESSAGE_DATA function is used to read any additional data
+on an incoming message, and to set custom data on an outbound message. It was
+designed to be protocol-agnostic, but is currently only implemented for SIP
+messages. All SIP headers of an incoming SIP message are accessable.
+MESSAGE_DATA() may also be used to add custom SIP headers to an outbound
+message.
+
+ MESSAGE_DATA(<argument>):
+ argument - The key of the data to retrieve. For example, to retrieve
+ the value of the SIP contact header, use "contact" as the
+ argument.
+
+ To add a custom header "x-custom", call Set(MESSAGE_DATA(x-custom)=val).
+To pass a custom header from an inbound message, call
+Set(MESSAGE_DATA(x-custom)=${MESSAGE_DATA(x-custom)}).
+
+--- 2.3) MessageSend() Application
One of the most important part of the dialplan for messages is forwarding
the message on to another destination. For that, a new dialplan application is
@@ -137,7 +157,7 @@
to deliver the message for some reason.
---- 2.3) Dialplan Examples
+--- 2.4) Dialplan Examples
Example 1:
Modified: team/russell/messaging/include/asterisk/message.h
URL: http://svnview.digium.com/svn/asterisk/team/russell/messaging/include/asterisk/message.h?view=diff&rev=315987&r1=315986&r2=315987
==============================================================================
--- team/russell/messaging/include/asterisk/message.h (original)
+++ team/russell/messaging/include/asterisk/message.h Wed Apr 27 15:21:55 2011
@@ -115,30 +115,65 @@
/*!
* \brief Set the 'to' URI of a message
+ *
+ * \retval 0 success
+ * \retval -1 failure
*/
int __attribute__((format(printf, 2, 3)))
ast_msg_set_to(struct ast_msg *msg, const char *fmt, ...);
/*!
* \brief Set the 'from' URI of a message
+ *
+ * \retval 0 success
+ * \retval -1 failure
*/
int __attribute__((format(printf, 2, 3)))
ast_msg_set_from(struct ast_msg *msg, const char *fmt, ...);
/*!
* \brief Set the 'body' text of a message (in UTF-8)
+ *
+ * \retval 0 success
+ * \retval -1 failure
*/
int __attribute__((format(printf, 2, 3)))
ast_msg_set_body(struct ast_msg *msg, const char *fmt, ...);
/*!
* \brief Set the dialplan context for this message
+ *
+ * \retval 0 success
+ * \retval -1 failure
*/
int __attribute__((format(printf, 2, 3)))
ast_msg_set_context(struct ast_msg *msg, const char *fmt, ...);
/*!
+ * \brief Set a variable on the message
+ * \note Setting a variable that already exists overwrites the existing variable value
+ *
+ * \param name Name of variable to set
+ * \param value Value of variable to set
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int ast_msg_set_var(struct ast_msg *msg, const char *name, const char *value);
+
+/*!
+ * \brief Get the specified variable on the message
+ * \note The return value is valid only as long as the ast_message is valid. Hold a reference
+ * to the message if you plan on storing the return value.
+ *
+ * \return The value associated with variable "name". NULL if variable not found.
+ */
+const char *ast_msg_get_var(struct ast_msg *msg, const char *name);
+
+/*!
* \brief Get the body of a message.
+ * \note The return value is valid only as long as the ast_message is valid. Hold a reference
+ * to the message if you plan on storing the return value.
*
* \return The body of the messsage, encoded in UTF-8.
*/
@@ -154,6 +189,42 @@
* \retval non-zero failure, message not sent to dialplan
*/
int ast_msg_queue(struct ast_msg *msg);
+
+/*!
+ * \brief Opaque iterator for msg variables
+ */
+struct ast_msg_var_iterator;
+
+/*!
+ * \brief Create a new message variable iterator
+ * \param msg A message whose variables are to be iterated over
+ *
+ * \return An opaque pointer to the new iterator
+ */
+struct ast_msg_var_iterator *ast_msg_var_iterator_init(const struct ast_msg *msg);
+
+/*!
+ * \brief Get the next variable name and value that is set for sending outbound
+ * \param msg The message with the variables
+ * \param i An iterator created with ast_msg_var_iterator_init
+ * \param name A pointer to the name result pointer
+ * \param value A pointer to the value result pointer
+ *
+ * \retval 0 No more entries
+ * \retval 1 Valid entry
+ */
+int ast_msg_var_iterator_next(const struct ast_msg *msg, struct ast_msg_var_iterator *i, const char **name, const char **value);
+
+/*!
+ * \brief Destroy a message variable iterator
+ * \param i Iterator to be destroyed
+ */
+void ast_msg_var_iterator_destroy(struct ast_msg_var_iterator *i);
+
+/*!
+ * \brief Unref a message var from inside an iterator loop
+ */
+void ast_msg_var_unref_current(struct ast_msg_var_iterator *i);
#if defined(__cplusplus) || defined(c_plusplus)
}
Modified: team/russell/messaging/main/message.c
URL: http://svnview.digium.com/svn/asterisk/team/russell/messaging/main/message.c?view=diff&rev=315987&r1=315986&r2=315987
==============================================================================
--- team/russell/messaging/main/message.c (original)
+++ team/russell/messaging/main/message.c Wed Apr 27 15:21:55 2011
@@ -75,6 +75,26 @@
<ref type="application">MessageSend</ref>
</see-also>
</function>
+ <function name="MESSAGE_DATA" language="en_US">
+ <synopsis>
+ Read or write custom data attached to a message.
+ </synopsis>
+ <syntax argsep="/">
+ <parameter name="argument" required="true">
+ <para>Field of the message to get or set.</para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>This function will read from or write a value to a text message.
+ It is used both to read the data out of an incoming message, as well as
+ modify a message that will be sent outbound.</para>
+ <para>NOTE: If you want to set an outbound message to carry data in the
+ current message, do Set(MESSAGE_DATA(key)=${MESSAGE_DATA(key)}).</para>
+ </description>
+ <see-also>
+ <ref type="application">MessageSend</ref>
+ </see-also>
+ </function>
<application name="MessageSend" language="en_US">
<synopsis>
Send a text message.
@@ -114,6 +134,16 @@
</application>
***/
+struct msg_data {
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(name);
+ AST_STRING_FIELD(value);
+ );
+ unsigned int send:1; /* Whether to send out on outbound messages */
+};
+
+AST_LIST_HEAD_NOLOCK(outhead, msg_data);
+
/*!
* \brief A message.
*
@@ -124,6 +154,7 @@
struct ast_str *from;
struct ast_str *body;
struct ast_str *context;
+ struct ao2_container *vars;
};
struct ast_msg_tech_holder {
@@ -161,6 +192,17 @@
.write = msg_func_write,
};
+static int msg_data_func_read(struct ast_channel *chan, const char *function,
+ char *data, char *buf, size_t len);
+static int msg_data_func_write(struct ast_channel *chan, const char *function,
+ char *data, const char *value);
+
+static struct ast_custom_function msg_data_function = {
+ .name = "MESSAGE_DATA",
+ .read = msg_data_func_read,
+ .write = msg_data_func_write,
+};
+
static struct ast_frame *chan_msg_read(struct ast_channel *chan);
static int chan_msg_write(struct ast_channel *chan, struct ast_frame *fr);
static int chan_msg_indicate(struct ast_channel *chan, int condition,
@@ -260,6 +302,24 @@
ao2_ref(msg, -1);
}
+static int msg_data_hash_fn(const void *obj, const int flags)
+{
+ const struct msg_data *data = obj;
+ return ast_str_case_hash(data->name);
+}
+
+static int msg_data_cmp_fn(void *obj, void *arg, int flags)
+{
+ const struct msg_data *one = obj, *two = arg;
+ return !strcasecmp(one->name, two->name) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+static void msg_data_destructor(void *obj)
+{
+ struct msg_data *data = obj;
+ ast_string_field_free_memory(data);
+}
+
static void msg_destructor(void *obj)
{
struct ast_msg *msg = obj;
@@ -275,6 +335,8 @@
ast_free(msg->context);
msg->context = NULL;
+
+ ao2_ref(msg->vars, -1);
}
struct ast_msg *ast_msg_alloc(void)
@@ -304,6 +366,12 @@
ao2_ref(msg, -1);
return NULL;
}
+
+ if (!(msg->vars = ao2_container_alloc(1, msg_data_hash_fn, msg_data_cmp_fn))) {
+ ao2_ref(msg, -1);
+ return NULL;
+ }
+
ast_str_set(&msg->context, 0, "default");
return msg;
@@ -367,6 +435,133 @@
const char *ast_msg_get_body(const struct ast_msg *msg)
{
return ast_str_buffer(msg->body);
+}
+
+static struct msg_data *msg_data_alloc(void)
+{
+ struct msg_data *data;
+
+ if (!(data = ao2_alloc(sizeof(*data), msg_data_destructor))) {
+ return NULL;
+ }
+
+ if (ast_string_field_init(data, 32)) {
+ ao2_ref(data, -1);
+ return NULL;
+ }
+
+ return data;
+}
+
+static struct msg_data *msg_data_find(struct ao2_container *vars, const char *name)
+{
+ struct msg_data tmp = {
+ .name = name,
+ };
+ return ao2_find(vars, &tmp, OBJ_POINTER);
+}
+
+static int msg_set_var_full(struct ast_msg *msg, const char *name, const char *value, unsigned int outbound)
+{
+ struct msg_data *data;
+
+ if (!(data = msg_data_find(msg->vars, name))) {
+ if (!(data = msg_data_alloc())) {
+ return -1;
+ };
+
+ ast_string_field_set(data, name, name);
+ ast_string_field_set(data, value, value);
+ data->send = outbound;
+ ao2_link(msg->vars, data);
+ } else {
+ if (ast_strlen_zero(value)) {
+ ao2_unlink(msg->vars, data);
+ } else {
+ ast_string_field_set(data, value, value);
+ data->send = outbound;
+ }
+ }
+
+ ao2_ref(data, -1);
+
+ return 0;
+}
+
+static int msg_set_var_outbound(struct ast_msg *msg, const char *name, const char *value)
+{
+ return msg_set_var_full(msg, name, value, 1);
+}
+
+int ast_msg_set_var(struct ast_msg *msg, const char *name, const char *value)
+{
+ return msg_set_var_full(msg, name, value, 0);
+}
+
+const char *ast_msg_get_var(struct ast_msg *msg, const char *name)
+{
+ struct msg_data *data;
+
+ if (!(data = msg_data_find(msg->vars, name))) {
+ return NULL;
+ }
+
+ return data->value;
+}
+
+struct ast_msg_var_iterator {
+ struct ao2_iterator i;
+ struct msg_data *current_used;
+};
+
+struct ast_msg_var_iterator *ast_msg_var_iterator_init(const struct ast_msg *msg)
+{
+ struct ast_msg_var_iterator *i;
+ if (!(i = ast_calloc(1, sizeof(*i)))) {
+ return NULL;
+ }
+
+ i->i = ao2_iterator_init(msg->vars, 0);
+
+ return i;
+}
+
+int ast_msg_var_iterator_next(const struct ast_msg *msg, struct ast_msg_var_iterator *i, const char **name, const char **value)
+{
+ struct msg_data *data;
+
+ /* Skip any that aren't marked for sending out */
+ while ((data = ao2_iterator_next(&i->i)) && !data->send) {
+ ao2_ref(data, -1);
+ }
+
+ if (!data) {
+ return 0;
+ }
+
+ if (data->send) {
+ *name = data->name;
+ *value = data->value;
+ }
+
+ /* Leave the refcount to be cleaned up by the caller with
+ * ast_msg_var_unref_current after they finish with the pointers to the data */
+ i->current_used = data;
+
+ return 1;
+}
+
+void ast_msg_var_unref_current(struct ast_msg_var_iterator *i) {
+ if (i->current_used) {
+ ao2_ref(i->current_used, -1);
+ }
+ i->current_used = NULL;
+}
+
+void ast_msg_var_iterator_destroy(struct ast_msg_var_iterator *i)
+{
+ ao2_iterator_destroy(&i->i);
+ ast_free(i);
}
static struct ast_channel *create_msg_q_chan(void)
@@ -626,6 +821,63 @@
return 0;
}
+static int msg_data_func_read(struct ast_channel *chan, const char *function,
+ char *data, char *buf, size_t len)
+{
+ struct ast_datastore *ds;
+ struct ast_msg *msg;
+ const char *val;
+
+ ast_channel_lock(chan);
+
+ if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
+ ast_channel_unlock(chan);
+ ast_log(LOG_ERROR, "No MESSAGE data found on the channel to read.\n");
+ return -1;
+ }
+
+ msg = ds->data;
+ ao2_ref(msg, +1);
+ ast_channel_unlock(chan);
+
+ ao2_lock(msg);
+
+ if ((val = ast_msg_get_var(msg, data))) {
+ ast_copy_string(buf, val, len);
+ }
+
+ ao2_unlock(msg);
+ ao2_ref(msg, -1);
+
+ return 0;
+}
+
+static int msg_data_func_write(struct ast_channel *chan, const char *function,
+ char *data, const char *value)
+{
+ struct ast_datastore *ds;
+ struct ast_msg *msg;
+
+ ast_channel_lock(chan);
+
+ if (!(ds = msg_datastore_find_or_create(chan))) {
+ ast_channel_unlock(chan);
+ return -1;
+ }
+
+ msg = ds->data;
+ ao2_ref(msg, +1);
+ ast_channel_unlock(chan);
+
+ ao2_lock(msg);
+
+ msg_set_var_outbound(msg, data, value);
+
+ ao2_unlock(msg);
+ ao2_ref(msg, -1);
+
+ return 0;
+}
static int msg_tech_hash(const void *obj, const int flags)
{
struct ast_msg_tech_holder *tech_holder = (struct ast_msg_tech_holder *) obj;
@@ -831,6 +1083,7 @@
}
res = __ast_custom_function_register(&msg_function, NULL);
+ res |= __ast_custom_function_register(&msg_data_function, NULL);
res |= ast_register_application2(app_msg_send, msg_send_exec, NULL, NULL, NULL);
return res;
More information about the asterisk-commits
mailing list