diff options
author | Matthew Jordan <mjordan@digium.com> | 2014-08-05 21:44:09 +0000 |
---|---|---|
committer | Matthew Jordan <mjordan@digium.com> | 2014-08-05 21:44:09 +0000 |
commit | 47bf7efc4dd2fbfe1b027f989e5152ef93f97a5b (patch) | |
tree | 29d79ec246df25e3f41e36d00d13249595f79e23 /res/res_pjsip_messaging.c | |
parent | fb2adba3cae37981b38add01e91108ae9c08ada2 (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.c | 129 |
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; } |