137#define MAX_HDR_SIZE 512
138#define MAX_BODY_SIZE 1024
139#define MAX_USER_SIZE 128
155 if (rdata->msg_info.msg->body && rdata->msg_info.msg->body->len) {
157 &rdata->msg_info.msg->body->content_type,
"text",
"plain");
159 res = rdata->msg_info.ctype &&
161 &rdata->msg_info.ctype->media,
"text",
"plain");
164 return res ? PJSIP_SC_OK : PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
178 int res = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
179 static const pj_str_t
text = {
"text", 4};
180 static const pj_str_t application = {
"application", 11};
182 if (!(rdata->msg_info.msg->body && rdata->msg_info.msg->body->len > 0)) {
187 if (pj_stricmp(&rdata->msg_info.msg->body->content_type.type, &
text) == 0
188 || pj_stricmp(&rdata->msg_info.msg->body->content_type.type, &application) == 0) {
190 }
else if (rdata->msg_info.ctype
191 && (pj_stricmp(&rdata->msg_info.ctype->media.type, &
text) == 0
192 || pj_stricmp(&rdata->msg_info.ctype->media.type, &application) == 0)) {
210 pjsip_name_addr *parsed_name_addr;
212 parsed_name_addr = (pjsip_name_addr *) pjsip_parse_uri(tdata->pool, to, strlen(to),
213 PJSIP_PARSE_URI_AS_NAMEADDR);
215 if (parsed_name_addr) {
216 if (pj_strlen(&parsed_name_addr->display)) {
217 pjsip_name_addr *name_addr =
218 (pjsip_name_addr *) PJSIP_MSG_TO_HDR(tdata->msg)->uri;
220 pj_strdup(tdata->pool, &name_addr->display, &parsed_name_addr->display);
246 static const char *hdr[] = {
261 if (!strcasecmp(
name, hdr[i])) {
286 if (!strcasecmp(
name,
"Max-Forwards")) {
317 pjsip_hdr *h = rdata->msg_info.msg->hdr.
next;
318 pjsip_hdr *
end= &rdata->msg_info.msg->hdr;
321 if ((res = pjsip_hdr_print_on(h,
buf,
sizeof(
buf)-1)) > 0) {
323 if ((
c = strchr(
buf,
':'))) {
352 if (!rdata->msg_info.msg->body || !rdata->msg_info.msg->body->len) {
356 if ((res = rdata->msg_info.msg->body->print_body(
357 rdata->msg_info.msg->body,
buf,
len)) < 0) {
362 while (res > 0 && ((
buf[--res] ==
'\r') || (
buf[res] ==
'\n')));
390 scheme = strncmp(
buf,
"sip", 3) ?
"pjsip:" :
"pj";
391 count = strlen(scheme);
392 if (count + size >= capacity) {
394 "too large for given buffer\n");
398 memmove(res + count,
buf, size);
399 memcpy(res, scheme, count);
422 pjsip_uri *ruri = rdata->msg_info.msg->line.req.uri;
423 pjsip_name_addr *name_addr;
434 return PJSIP_SC_UNSUPPORTED_URI_SCHEME;
448 context =
S_OR(endpt->message_context, endpt->context);
453 name_addr = (pjsip_name_addr *)rdata->msg_info.to->uri;
454 size = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, name_addr,
buf,
sizeof(
buf) - 1);
456 return PJSIP_SC_INTERNAL_SERVER_ERROR;
471 name_addr = (pjsip_name_addr *)rdata->msg_info.from->uri;
472 suri = pjsip_uri_get_uri((pjsip_uri *)name_addr);
473 if (name_addr->display.slen > 0) {
475 char *temp_name =
ast_alloca(name_addr->display.slen + 1);
476 for (i = 0; i < name_addr->display.slen; i++) {
477 if (name_addr->display.ptr[i] < 32) {
480 temp_name[i] = name_addr->display.ptr[i];
483 temp_name[name_addr->display.slen] =
'\0';
488 display_name =
ast_alloca(name_addr->display.slen + 5);
489 size = sprintf(display_name,
"\"%s\" ", temp_name);
507 field = pj_sockaddr_print(&rdata->pkt_info.src_addr,
buf,
sizeof(
buf) - 1, 3);
510 switch (rdata->tp_info.transport->key.type) {
511 case PJSIP_TRANSPORT_UDP:
512 case PJSIP_TRANSPORT_UDP6:
515 case PJSIP_TRANSPORT_TCP:
516 case PJSIP_TRANSPORT_TCP6:
519 case PJSIP_TRANSPORT_TLS:
520 case PJSIP_TRANSPORT_TLS6:
524 field = rdata->tp_info.transport->type_name;
535 if (endpt->id.self.name.valid) {
536 res |=
ast_msg_set_var(msg,
"PJSIP_ENDPOINT", endpt->id.self.name.str);
541 return !res ? PJSIP_SC_OK : PJSIP_SC_INTERNAL_SERVER_ERROR;
616 const char *initial_uri)
631 ast_log(
LOG_ERROR,
"Failed to allocate memory for response data strings on endpoint '%s'.\n",
649 static const pj_str_t CONTENT_TYPE = {
"Content-Type",
sizeof(
"Content-Type") - 1 };
653 pj_str_t
type, subtype;
654 pjsip_ctype_hdr *parsed;
657 parsed = pjsip_parse_hdr(tdata->pool, &CONTENT_TYPE,
668 pj_strdup_with_null(tdata->pool, &
type, &parsed->media.type);
669 pj_strdup_with_null(tdata->pool, &subtype, &parsed->media.subtype);
672 body->subtype = pj_strbuf(&subtype);
690 pjsip_tx_data *tdata;
696 .body_text = resp_data->
body
700 ast_log(
LOG_ERROR,
"No redirect state available for sending a redirect message.\n");
706 ast_debug(1,
"Sending redirected MESSAGE to '%s' (hop %d) on endpoint '%s'\n",
728 char *
subtype = strchr(type_copy,
'/');
732 body.
type = type_copy;
737 if (!tdata->msg->body) {
738 pjsip_tx_data_dec_ref(tdata);
745 if (!new_resp_data) {
746 pjsip_tx_data_dec_ref(tdata);
759 pjsip_tx_data_dec_ref(tdata);
761 ast_log(
LOG_ERROR,
"Failed to allocate memory for redirect callback strings for endpoint '%s'.\n",
773 ast_log(
LOG_ERROR,
"Failed to send redirect request to '%s' on endpoint '%s'.\n",
800 ast_debug(1,
"MESSAGE redirect on endpoint '%s': not following redirect (parse failed or conditions not met)\n",
813 ast_log(
LOG_NOTICE,
"MESSAGE redirect on endpoint '%s': Following redirect to '%s' (hop %d/%d)\n",
833 pjsip_rx_data *rdata;
835 char *next_uri =
NULL;
838 if (e->body.tsx_state.type == PJSIP_EVENT_TIMER) {
842 ast_log(
LOG_NOTICE,
"MESSAGE timed out on endpoint '%s', trying next Contact: '%s'\n",
851 if (e->body.tsx_state.type != PJSIP_EVENT_RX_MSG) {
852 ast_debug(3,
"MESSAGE response event type %d (not RX_MSG) on endpoint '%s'.\n",
858 rdata = e->body.tsx_state.src.rdata;
859 status_code = e->body.tsx_state.tsx->status_code;
864 if (PJSIP_IS_STATUS_IN_CLASS(status_code, 300)) {
869 ast_log(
LOG_NOTICE,
"MESSAGE to redirect target failed (%d) on endpoint '%s', trying next Contact: '%s'\n",
875 else if (PJSIP_IS_STATUS_IN_CLASS(status_code, 200)) {
906 const char *from_uri;
915 pjsip_tx_data *tdata;
920 ast_debug(3,
"mdata From: %s msg From: %s mdata Destination: %s msg To: %s\n",
926 "PJSIP MESSAGE - Could not find endpoint '%s' and no default outbound endpoint configured\n",
932 "MdataDestination: %s\r\n"
979 pjsip_name_addr *tdata_name_addr;
980 pjsip_sip_uri *tdata_sip_uri;
984 tdata_name_addr = (pjsip_name_addr *) PJSIP_MSG_TO_HDR(tdata->msg)->uri;
985 tdata_sip_uri = pjsip_uri_get_uri(tdata_name_addr->uri);
986 pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, tdata_sip_uri, touri,
sizeof(touri));
987 tdata_name_addr = (pjsip_name_addr *) PJSIP_MSG_FROM_HDR(tdata->msg)->uri;
988 tdata_sip_uri = pjsip_uri_get_uri(tdata_name_addr->uri);
989 pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, tdata_sip_uri, fromuri,
sizeof(fromuri));
994 "MdataDestination: %s\r\n"
1015 if (!tdata->msg->body) {
1016 pjsip_tx_data_dec_ref(tdata);
1027 ast_debug(1,
"Sending message to '%s' (via endpoint %s) from '%s'\n",
1032 from_uri = mdata->
from;
1054 pjsip_tx_data_dec_ref(tdata);
1055 ast_log(
LOG_ERROR,
"PJSIP MESSAGE - Could not allocate callback data for endpoint '%s'\n",
1096static pj_status_t
send_response(pjsip_rx_data *rdata,
enum pjsip_status_code code,
1097 pjsip_dialog *dlg, pjsip_transaction *tsx)
1099 pjsip_tx_data *tdata;
1103 if (
status != PJ_SUCCESS) {
1109 status = pjsip_dlg_send_response(dlg, tsx, tdata);
1118 if (
status != PJ_SUCCESS) {
1127 enum pjsip_status_code code;
1136 if (code != PJSIP_SC_OK) {
1148 if (code != PJSIP_SC_OK) {
1155 ast_debug(1,
"MESSAGE request received, but no handler wanted it\n");
1177 enum pjsip_status_code code;
1179 pjsip_dialog *dlg =
session->inv_session->dlg;
1180 pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
1183 pjsip_name_addr *name_addr;
1196 if (code != PJSIP_SC_OK) {
1203 name_addr = (pjsip_name_addr *) rdata->msg_info.from->uri;
1204 from_len = pj_strlen(&name_addr->display);
1217 name_addr = (pjsip_name_addr *) rdata->msg_info.to->uri;
1218 to_len = pj_strlen(&name_addr->display);
1228 attrs[pos].
value =
ast_alloca(rdata->msg_info.msg->body->content_type.type.slen
1229 + rdata->msg_info.msg->body->content_type.subtype.slen + 2);
1230 sprintf(attrs[pos].
value,
"%.*s/%.*s",
1231 (
int)rdata->msg_info.msg->body->content_type.
type.slen,
1232 rdata->msg_info.msg->body->content_type.type.ptr,
1233 (
int)rdata->msg_info.msg->body->content_type.subtype.slen,
1234 rdata->msg_info.msg->body->content_type.subtype.ptr);
1240 if (!attrs[pos].
value) {
1241 send_response(rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, dlg, tsx);
1244 ast_copy_string(attrs[pos].
value, rdata->msg_info.msg->body->data, rdata->msg_info.msg->body->len + 1);
1250 send_response(rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, dlg, tsx);
1254 ast_debug(1,
"Received in-dialog MESSAGE from '%s:%s': %s %s\n",
1264 send_response(rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, dlg, tsx);
1278 .name = {
"Messaging Module", 16},
1280 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
1328 .
requires =
"res_pjsip,res_pjsip_session",
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_mansession session
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
#define ast_strdup(str)
A wrapper for strdup()
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ast_malloc(len)
A wrapper for malloc()
@ AO2_ALLOC_OPT_LOCK_NOLOCK
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define ao2_alloc_options(data_size, destructor_fn, options)
#define ao2_alloc(data_size, destructor_fn)
const char * ast_channel_name(const struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
#define AST_MAX_EXTENSION
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
const char * ast_msg_data_get_attribute(struct ast_msg_data *msg, enum ast_msg_data_attribute_type attribute_type)
Get attribute from ast_msg_data.
struct ast_msg_data * ast_msg_data_alloc(enum ast_msg_data_source_type source, struct ast_msg_data_attribute attributes[], size_t count)
Allocates an ast_msg_data structure.
int ast_msg_data_queue_frame(struct ast_channel *channel, struct ast_msg_data *msg)
Queue an AST_FRAME_TEXT_DATA frame containing an ast_msg_data structure.
@ AST_MSG_DATA_ATTR_CONTENT_TYPE
@ AST_MSG_DATA_SOURCE_TYPE_IN_DIALOG
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
#define ast_sip_push_task_wait_serializer(serializer, sip_task, task_data)
#define ast_debug(level,...)
Log a DEBUG message.
Out-of-call text message support.
int ast_msg_set_from(struct ast_msg *msg, const char *fmt,...)
Set the 'from' URI of a message.
const char * ast_msg_get_var(struct ast_msg *msg, const char *name)
Get the specified variable on the message.
const char * ast_msg_get_from(const struct ast_msg *msg)
Retrieve the source of this message.
void ast_msg_var_iterator_destroy(struct ast_msg_var_iterator *iter)
Destroy a message variable iterator.
struct ast_msg * ast_msg_destroy(struct ast_msg *msg)
Destroy an ast_msg.
int ast_msg_set_endpoint(struct ast_msg *msg, const char *fmt,...)
Set the technology's endpoint associated with this message.
int ast_msg_var_iterator_next(const struct ast_msg *msg, struct ast_msg_var_iterator *iter, const char **name, const char **value)
Get the next variable name and value that is set for sending outbound.
int ast_msg_set_exten(struct ast_msg *msg, const char *fmt,...)
Set the dialplan extension for this message.
int ast_msg_set_tech(struct ast_msg *msg, const char *fmt,...)
Set the technology associated with this message.
int ast_msg_has_destination(const struct ast_msg *msg)
Determine if a particular message has a destination via some handler.
struct ast_msg * ast_msg_alloc(void)
Allocate a message.
int ast_msg_tech_unregister(const struct ast_msg_tech *tech)
Unregister a message technology.
int ast_msg_set_var(struct ast_msg *msg, const char *name, const char *value)
Set a variable on the message going to the dialplan.
const char * ast_msg_get_to(const struct ast_msg *msg)
Retrieve the destination of this message.
int ast_msg_tech_register(const struct ast_msg_tech *tech)
Register a message technology.
const char * ast_msg_get_body(const struct ast_msg *msg)
Get the body of a message.
int ast_msg_set_context(struct ast_msg *msg, const char *fmt,...)
Set the dialplan context for this message.
int ast_msg_set_body(struct ast_msg *msg, const char *fmt,...)
Set the 'body' text of a message (in UTF-8)
int ast_msg_set_to(struct ast_msg *msg, const char *fmt,...)
Set the 'to' URI of a message.
void ast_msg_var_unref_current(struct ast_msg_var_iterator *iter)
Unref a message var from inside an iterator loop.
struct ast_msg_var_iterator * ast_msg_var_iterator_init(const struct ast_msg *msg)
Create a new message variable iterator.
int ast_msg_queue(struct ast_msg *msg)
Queue a message for routing through the dialplan.
struct ast_msg * ast_msg_ref(struct ast_msg *msg)
Bump a msg's ref count.
Asterisk module definitions.
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
@ AST_MODULE_SUPPORT_CORE
#define ASTERISK_GPL_KEY
The text the key() function should return.
@ AST_MODULE_LOAD_SUCCESS
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Core PBX routines and definitions.
struct ast_sip_endpoint * ast_sip_get_endpoint(const char *to, int get_default_outbound, char **uri)
Retrieves an endpoint and URI from the "to" string.
const pj_str_t * ast_sip_pjsip_uri_get_username(pjsip_uri *uri)
Get the user portion of the pjsip_uri.
void ast_sip_unregister_service(pjsip_module *module)
int ast_sip_create_response(const pjsip_rx_data *rdata, int st_code, struct ast_sip_contact *contact, pjsip_tx_data **p_tdata)
General purpose method for creating a SIP response.
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
int ast_sip_is_allowed_uri(pjsip_uri *uri)
Check whether a pjsip_uri is allowed or not.
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
int ast_sip_update_from(pjsip_tx_data *tdata, char *from)
Overwrite fields in the outbound 'From' header.
struct ast_sip_endpoint * ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata)
Get the looked-up endpoint on an out-of dialog request or response.
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint, void *token, void(*callback)(void *token, pjsip_event *e))
General purpose method for sending a SIP request.
int ast_sip_add_body(pjsip_tx_data *tdata, const struct ast_sip_body *body)
Add a body to an outbound SIP message.
int ast_sip_update_to_uri(pjsip_tx_data *tdata, const char *to)
Replace the To URI in the tdata with the supplied one.
int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint, const char *uri, struct ast_sip_contact *contact, pjsip_tx_data **tdata)
General purpose method for creating a SIP request.
int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value)
Add a header to an outbound SIP message.
const pj_str_t * ast_sip_pjsip_uri_get_hostname(pjsip_uri *uri)
Get the host portion of the pjsip_uri.
#define PJSTR_PRINTF_VAR(_v)
int ast_sip_send_stateful_response(pjsip_rx_data *rdata, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint)
Send a stateful response to an out of dialog request.
int ast_sip_is_content_type(pjsip_media_type *content_type, char *type, char *subtype)
Checks if the given content type matches type/subtype.
#define PJSTR_PRINTF_SPEC
static struct message_response_data * message_response_data_create(struct ast_sip_endpoint *endpoint, const char *from, const char *to, const char *body, const char *content_type, const char *initial_uri)
static void msg_response_callback(void *token, pjsip_event *e)
static struct ast_sip_session_supplement messaging_supplement
static enum pjsip_status_code vars_to_headers(const struct ast_msg *msg, pjsip_tx_data *tdata)
static void handle_message_redirect(struct message_response_data *resp_data, pjsip_rx_data *rdata)
static pj_bool_t module_on_rx_request(pjsip_rx_data *rdata)
static int incoming_in_dialog_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
static enum pjsip_status_code check_content_type(const pjsip_rx_data *rdata)
static enum pjsip_status_code check_content_type_in_dialog(const pjsip_rx_data *rdata)
static enum pjsip_status_code rx_data_to_ast_msg(pjsip_rx_data *rdata, struct ast_msg *msg)
static int print_body(pjsip_rx_data *rdata, char *buf, int len)
static void msg_data_destroy(void *obj)
static pjsip_module messaging_module
static int msg_send(void *data)
static void message_response_data_destroy(void *obj)
static void update_content_type(pjsip_tx_data *tdata, struct ast_msg *msg, struct ast_sip_body *body)
static int load_module(void)
static int send_message_to_uri(struct message_response_data *resp_data, const char *target_uri)
static struct msg_data * msg_data_create(const struct ast_msg *msg, const char *destination, const char *from)
static struct ast_taskprocessor * message_serializer
static int unload_module(void)
static const struct ast_msg_tech msg_tech
static int is_msg_var_blocked(const char *name)
const pjsip_method pjsip_message_method
static int headers_to_vars(const pjsip_rx_data *rdata, struct ast_msg *msg)
static pj_status_t send_response(pjsip_rx_data *rdata, enum pjsip_status_code code, pjsip_dialog *dlg, pjsip_transaction *tsx)
static int update_to_display_name(pjsip_tx_data *tdata, char *to)
static int sip_msg_send(const struct ast_msg *msg, const char *destination, const char *from)
int ast_sip_redirect_parse_3xx(pjsip_rx_data *rdata, struct ast_sip_redirect_state *state)
Parse a 3xx redirect response and extract contacts.
int ast_sip_redirect_get_next_uri(struct ast_sip_redirect_state *state, char **uri_out)
Get the next redirect URI to try.
#define AST_SIP_MAX_REDIRECT_HOPS
Maximum number of redirect hops allowed.
struct ast_sip_endpoint * ast_sip_redirect_get_endpoint(const struct ast_sip_redirect_state *state)
Get the endpoint from the redirect state.
int ast_sip_redirect_get_hop_count(const struct ast_sip_redirect_state *state)
Get the current hop count.
void ast_sip_redirect_state_destroy(struct ast_sip_redirect_state *state)
Destroy a redirect state and free all resources.
struct ast_sip_redirect_state * ast_sip_redirect_state_create(struct ast_sip_endpoint *endpoint, const char *initial_uri)
Create a new redirect state.
#define ast_sip_session_register_supplement(supplement)
void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
Unregister a an supplement to SIP session processing.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
char *attribute_pure ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
enum ast_msg_data_attribute_type type
Structure used to transport a message through the frame core.
const char *const name
Name of this message technology.
Caller Party information.
struct ast_party_id id
Caller party ID.
struct ast_party_name name
Subscriber name.
unsigned char valid
TRUE if the name information is valid/present.
char * str
Subscriber name (Malloced)
An entity with which Asterisk communicates.
Redirect state structure.
A supplement to SIP message processing.
struct ast_module *const char * method
A structure describing a SIP session.
Support for dynamic strings.
A ast_taskprocessor structure is a singleton by name.
Channel datastore data for max forwards.
struct ast_sip_redirect_state * redirect_state
An API for managing task processing threads that can be shared across modules.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
#define ast_test_suite_event_notify(s, f,...)
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.