summaryrefslogtreecommitdiff
path: root/res/res_pjsip_messaging.c
diff options
context:
space:
mode:
authorMatthew Jordan <mjordan@digium.com>2014-08-05 21:44:09 +0000
committerMatthew Jordan <mjordan@digium.com>2014-08-05 21:44:09 +0000
commit47bf7efc4dd2fbfe1b027f989e5152ef93f97a5b (patch)
tree29d79ec246df25e3f41e36d00d13249595f79e23 /res/res_pjsip_messaging.c
parentfb2adba3cae37981b38add01e91108ae9c08ada2 (diff)
Multiple revisions 420089-420090,420097
........ r420089 | mjordan | 2014-08-05 15:10:52 -0500 (Tue, 05 Aug 2014) | 72 lines ARI: Add channel technology agnostic out of call text messaging This patch adds the ability to send and receive text messages from various technology stacks in Asterisk through ARI. This includes chan_sip (sip), res_pjsip_messaging (pjsip), and res_xmpp (xmpp). Messages are sent using the endpoints resource, and can be sent directly through that resource, or to a particular endpoint. For example, the following would send the message "Hello there" to PJSIP endpoint alice with a display URI of sip:asterisk@mycooldomain.org: ari/endpoints/sendMessage?to=pjsip:alice&from=sip:asterisk@mycooldomain.org&body=Hello+There This is equivalent to the following as well: ari/endpoints/PJSIP/alice/sendMessage?from=sip:asterisk@mycooldomain.org&body=Hello+There Both forms are available for message technologies that allow for arbitrary destinations, such as chan_sip. Inbound messages can now be received over ARI as well. An ARI application that subscribes to endpoints will receive messages from those endpoints: { "type": "TextMessageReceived", "timestamp": "2014-07-12T22:53:13.494-0500", "endpoint": { "technology": "PJSIP", "resource": "alice", "state": "online", "channel_ids": [] }, "message": { "from": "\"alice\" <sip:alice@127.0.0.1>", "to": "pjsip:asterisk@127.0.0.1", "body": "Watson, come here.", "variables": [] }, "application": "testsuite" } The above was made possible due to some rather major changes in the message core. This includes (but is not limited to): - Users of the message API can now register message handlers. A handler has two callbacks: one to determine if the handler has a destination for the message, and another to handle it. - All dialplan functionality of handling a message was moved into a message handler provided by the message API. - Messages can now have the technology/endpoint associated with them. Various other properties are also now more easily accessible. - A number of ao2 containers that weren't really needed were replaced with vectors. Iteration over ao2_containers is expensive and pointless when the lifetime of things is well defined and the number of things is very small. res_stasis now has a new file that makes up its structure, messaging. The messaging functionality implements a message handler, and passes received messages that match an interested endpoint over to the app for processing. Note that inadvertently while testing this, I reproduced ASTERISK-23969. res_pjsip_messaging was incorrectly parsing out the 'to' field, such that arbitrary SIP URIs mangled the endpoint lookup. This patch includes the fix for that as well. Review: https://reviewboard.asterisk.org/r/3726 ASTERISK-23692 #close Reported by: Matt Jordan ASTERISK-23969 #close Reported by: Andrew Nagy ........ r420090 | mjordan | 2014-08-05 15:16:37 -0500 (Tue, 05 Aug 2014) | 2 lines Remove automerge properties :-( ........ r420097 | mjordan | 2014-08-05 16:36:25 -0500 (Tue, 05 Aug 2014) | 2 lines test_message: Fix strict-aliasing compilation issue ........ Merged revisions 420089-420090,420097 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@420098 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res/res_pjsip_messaging.c')
-rw-r--r--res/res_pjsip_messaging.c129
1 files changed, 57 insertions, 72 deletions
diff --git a/res/res_pjsip_messaging.c b/res/res_pjsip_messaging.c
index f80261417..db9752553 100644
--- a/res/res_pjsip_messaging.c
+++ b/res/res_pjsip_messaging.c
@@ -47,40 +47,10 @@ const pjsip_method pjsip_message_method = {PJSIP_OTHER_METHOD, {"MESSAGE", 7} };
#define MAX_HDR_SIZE 512
#define MAX_BODY_SIZE 1024
-#define MAX_EXTEN_SIZE 256
#define MAX_USER_SIZE 128
/*!
* \internal
- * \brief Determine where in the dialplan a call should go
- *
- * \details This uses the username in the request URI to try to match
- * an extension in an endpoint's context in order to route the call.
- *
- * \param rdata The SIP request
- * \param context The context to use
- * \param exten The extension to use
- */
-static enum pjsip_status_code get_destination(const pjsip_rx_data *rdata, const char *context, char *exten)
-{
- pjsip_uri *ruri = rdata->msg_info.msg->line.req.uri;
- pjsip_sip_uri *sip_ruri;
-
- if (!PJSIP_URI_SCHEME_IS_SIP(ruri) && !PJSIP_URI_SCHEME_IS_SIPS(ruri)) {
- return PJSIP_SC_UNSUPPORTED_URI_SCHEME;
- }
-
- sip_ruri = pjsip_uri_get_uri(ruri);
- ast_copy_pj_str(exten, &sip_ruri->user, MAX_EXTEN_SIZE);
-
- if (ast_exists_extension(NULL, context, exten, 1, NULL)) {
- return PJSIP_SC_OK;
- }
- return PJSIP_SC_NOT_FOUND;
-}
-
-/*!
- * \internal
* \brief Checks to make sure the request has the correct content type.
*
* \details This module supports the following media types: "text/plain".
@@ -244,7 +214,6 @@ static void update_from(pjsip_tx_data *tdata, char *from)
PJSIP_PARSE_URI_AS_NAMEADDR))) {
pjsip_name_addr *parsed_name_addr = (pjsip_name_addr *)parsed;
pjsip_sip_uri *parsed_uri = pjsip_uri_get_uri(parsed_name_addr->uri);
-
if (pj_strlen(&parsed_name_addr->display)) {
pj_strdup(tdata->pool, &name_addr->display,
&parsed_name_addr->display);
@@ -458,58 +427,62 @@ static char *sip_to_pjsip(char *buf, int size, int capacity)
*/
static enum pjsip_status_code rx_data_to_ast_msg(pjsip_rx_data *rdata, struct ast_msg *msg)
{
-
-#define CHECK_RES(z_) do { if (z_) { ast_msg_destroy(msg); \
- return PJSIP_SC_INTERNAL_SERVER_ERROR; } } while (0)
-
- int size;
- char buf[MAX_BODY_SIZE];
+ struct ast_sip_endpoint *endpt = ast_pjsip_rdata_get_endpoint(rdata);
+ pjsip_uri *ruri = rdata->msg_info.msg->line.req.uri;
+ pjsip_sip_uri *sip_ruri;
pjsip_name_addr *name_addr;
+ char buf[MAX_BODY_SIZE];
const char *field;
- pjsip_status_code code;
- struct ast_sip_endpoint *endpt = ast_pjsip_rdata_get_endpoint(rdata);
const char *context = S_OR(endpt->message_context, endpt->context);
+ char exten[AST_MAX_EXTENSION];
+ int res = 0;
+ int size;
- /* make sure there is an appropriate context and extension*/
- if ((code = get_destination(rdata, context, buf)) != PJSIP_SC_OK) {
- return code;
+ if (!PJSIP_URI_SCHEME_IS_SIP(ruri) && !PJSIP_URI_SCHEME_IS_SIPS(ruri)) {
+ return PJSIP_SC_UNSUPPORTED_URI_SCHEME;
}
- CHECK_RES(ast_msg_set_context(msg, "%s", context));
- CHECK_RES(ast_msg_set_exten(msg, "%s", buf));
+ sip_ruri = pjsip_uri_get_uri(ruri);
+ ast_copy_pj_str(exten, &sip_ruri->user, AST_MAX_EXTENSION);
+
+ res |= ast_msg_set_context(msg, "%s", context);
+ res |= ast_msg_set_exten(msg, "%s", exten);
/* to header */
name_addr = (pjsip_name_addr *)rdata->msg_info.to->uri;
- if ((size = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, name_addr, buf, sizeof(buf)-1)) > 0) {
- buf[size] = '\0';
- /* prepend the tech */
- CHECK_RES(ast_msg_set_to(msg, "%s", sip_to_pjsip(buf, ++size, sizeof(buf)-1)));
+ size = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, name_addr, buf, sizeof(buf) - 1);
+ if (size <= 0) {
+ return PJSIP_SC_INTERNAL_SERVER_ERROR;
}
+ buf[size] = '\0';
+ res |= ast_msg_set_to(msg, "%s", sip_to_pjsip(buf, ++size, sizeof(buf) - 1));
/* from header */
name_addr = (pjsip_name_addr *)rdata->msg_info.from->uri;
- if ((size = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, name_addr, buf, sizeof(buf)-1)) > 0) {
- buf[size] = '\0';
- CHECK_RES(ast_msg_set_from(msg, "%s", buf));
+ size = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, name_addr, buf, sizeof(buf) - 1);
+ if (size <= 0) {
+ return PJSIP_SC_INTERNAL_SERVER_ERROR;
}
+ buf[size] = '\0';
+ res |= ast_msg_set_from(msg, "%s", buf);
- /* receive address */
- field = pj_sockaddr_print(&rdata->pkt_info.src_addr, buf, sizeof(buf)-1, 1);
- CHECK_RES(ast_msg_set_var(msg, "PJSIP_RECVADDR", field));
+ field = pj_sockaddr_print(&rdata->pkt_info.src_addr, buf, sizeof(buf) - 1, 1);
+ res |= ast_msg_set_var(msg, "PJSIP_RECVADDR", field);
- /* body */
if (print_body(rdata, buf, sizeof(buf) - 1) > 0) {
- CHECK_RES(ast_msg_set_body(msg, "%s", buf));
+ res |= ast_msg_set_body(msg, "%s", buf);
}
/* endpoint name */
+ res |= ast_msg_set_tech(msg, "%s", "PJSIP");
+ res |= ast_msg_set_endpoint(msg, "%s", ast_sorcery_object_get_id(endpt));
if (endpt->id.self.name.valid) {
- CHECK_RES(ast_msg_set_var(msg, "PJSIP_PEERNAME", endpt->id.self.name.str));
+ res |= ast_msg_set_var(msg, "PJSIP_ENDPOINT", endpt->id.self.name.str);
}
- CHECK_RES(headers_to_vars(rdata, msg));
+ res |= headers_to_vars(rdata, msg);
- return PJSIP_SC_OK;
+ return !res ? PJSIP_SC_OK : PJSIP_SC_INTERNAL_SERVER_ERROR;
}
struct msg_data {
@@ -547,17 +520,14 @@ static struct msg_data* msg_data_create(const struct ast_msg *msg, const char *t
return NULL;
}
- /* if there is another sip in the uri then we are good,
- otherwise it needs a sip: in front */
- mdata->to = to == skip_sip(to) ? ast_strdup(to - 3) :
- ast_strdup(++to);
+ /* Make sure we start with sip: */
+ mdata->to = ast_begins_with(to, "sip:") ? ast_strdup(++to) : ast_strdup(to - 3);
mdata->from = ast_strdup(from);
/* sometimes from can still contain the tag at this point, so remove it */
if ((tag = strchr(mdata->from, ';'))) {
*tag = '\0';
}
-
return mdata;
}
@@ -577,8 +547,8 @@ static int msg_send(void *data)
mdata->to, &uri), ao2_cleanup);
if (!endpoint) {
- ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not find endpoint and "
- "no default outbound endpoint configured\n");
+ ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not find endpoint '%s' and "
+ "no default outbound endpoint configured\n", mdata->to);
return -1;
}
@@ -598,6 +568,9 @@ static int msg_send(void *data)
vars_to_headers(mdata->msg, tdata);
+ ast_debug(1, "Sending message to '%s' (via endpoint %s) from '%s'\n",
+ mdata->to, ast_sorcery_object_get_id(endpoint), mdata->from);
+
if (ast_sip_send_request(tdata, NULL, endpoint, NULL, NULL)) {
ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not send request\n");
return -1;
@@ -670,24 +643,36 @@ static pj_bool_t module_on_rx_request(pjsip_rx_data *rdata)
return PJ_FALSE;
}
+ code = check_content_type(rdata);
+ if (code != PJSIP_SC_OK) {
+ send_response(rdata, code, NULL, NULL);
+ return PJ_TRUE;
+ }
+
msg = ast_msg_alloc();
if (!msg) {
send_response(rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL);
return PJ_TRUE;
}
- if ((code = check_content_type(rdata)) != PJSIP_SC_OK) {
+ code = rx_data_to_ast_msg(rdata, msg);
+ if (code != PJSIP_SC_OK) {
send_response(rdata, code, NULL, NULL);
+ ast_msg_destroy(msg);
return PJ_TRUE;
}
- if ((code = rx_data_to_ast_msg(rdata, msg)) == PJSIP_SC_OK) {
- /* send it to the dialplan */
- ast_msg_queue(msg);
- code = PJSIP_SC_ACCEPTED;
+ if (!ast_msg_has_destination(msg)) {
+ ast_debug(1, "MESSAGE request received, but no handler wanted it\n");
+ send_response(rdata, PJSIP_SC_NOT_FOUND, NULL, NULL);
+ ast_msg_destroy(msg);
+ return PJ_TRUE;
}
- send_response(rdata, code, NULL, NULL);
+ /* send it to the messaging core */
+ ast_msg_queue(msg);
+ send_response(rdata, PJSIP_SC_ACCEPTED, NULL, NULL);
+
return PJ_TRUE;
}