summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pjsip-apps/src/pjsua/pjsua_app.c87
-rw-r--r--pjsip/include/pjsip-simple/evsub.h12
-rw-r--r--pjsip/include/pjsip-ua/sip_inv.h15
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h11
-rw-r--r--pjsip/src/pjsip-simple/evsub.c21
-rw-r--r--pjsip/src/pjsip-ua/sip_inv.c40
-rw-r--r--pjsip/src/pjsip/sip_dialog.c10
-rw-r--r--pjsip/src/pjsua-lib/pjsua_acc.c4
-rw-r--r--pjsip/src/pjsua-lib/pjsua_core.c120
9 files changed, 303 insertions, 17 deletions
diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c
index e4fd5e85..999df2a5 100644
--- a/pjsip-apps/src/pjsua/pjsua_app.c
+++ b/pjsip-apps/src/pjsua/pjsua_app.c
@@ -137,7 +137,12 @@ static void usage(void)
/* Set default config. */
static void default_config(struct app_config *cfg)
{
+ char tmp[80];
+
pjsua_config_default(&cfg->cfg);
+ pj_ansi_sprintf(tmp, "PJSUA v%s/%s", PJ_VERSION, PJ_OS_NAME);
+ pj_strdup2_with_null(app_config.pool, &cfg->cfg.user_agent, tmp);
+
pjsua_logging_config_default(&cfg->log_cfg);
pjsua_media_config_default(&cfg->media_cfg);
pjsua_transport_config_default(&cfg->udp_cfg);
@@ -472,7 +477,7 @@ static pj_status_t parse_args(int argc, char *argv[],
case OPT_NEXT_ACCOUNT: /* Add more account. */
cfg->acc_cnt++;
- cur_acc = &cfg->acc_cfg[cfg->acc_cnt - 1];
+ cur_acc = &cfg->acc_cfg[cfg->acc_cnt];
break;
case OPT_USERNAME: /* Default authentication user */
@@ -664,8 +669,8 @@ static pj_status_t parse_args(int argc, char *argv[],
return PJ_EINVAL;
}
- if (cfg->acc_cfg[0].id.slen && cfg->acc_cnt==0)
- cfg->acc_cnt = 1;
+ if (cfg->acc_cfg[cfg->acc_cnt].id.slen)
+ cfg->acc_cnt++;
for (i=0; i<cfg->acc_cnt; ++i) {
if (cfg->acc_cfg[i].cred_info[cfg->acc_cfg[i].cred_count].username.slen)
@@ -1306,7 +1311,7 @@ static void keystroke_help(void)
puts("| dq Dump curr. call quality | cl List ports | d Dump status |");
puts("| | cc Connect port | dd Dump detailed |");
puts("| | cd Disconnect port | dc Dump config |");
- puts("| | | f Save config |");
+ puts("| S Send arbitrary REQUEST | | f Save config |");
puts("+------------------------------+--------------------------+-------------------+");
puts("| q QUIT |");
puts("+=============================================================================+");
@@ -1463,6 +1468,42 @@ static void conf_list(void)
/*
+ * Send arbitrary request to remote host
+ */
+static void send_request(char *cstr_method, const pj_str_t *dst_uri)
+{
+ pj_str_t str_method;
+ pjsip_method method;
+ pjsip_tx_data *tdata;
+ pjsua_acc_info acc_info;
+ pjsip_endpoint *endpt;
+ pj_status_t status;
+
+ endpt = pjsua_get_pjsip_endpt();
+
+ str_method = pj_str(cstr_method);
+ pjsip_method_init_np(&method, &str_method);
+
+ pjsua_acc_get_info(current_acc, &acc_info);
+
+ status = pjsip_endpt_create_request(endpt, &method, dst_uri,
+ &acc_info.acc_uri, dst_uri,
+ NULL, NULL, -1, NULL, &tdata);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Unable to create request", status);
+ return;
+ }
+
+ status = pjsip_endpt_send_request(endpt, tdata, -1, NULL, NULL);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Unable to send request", status);
+ pjsip_tx_data_dec_ref(tdata);
+ return;
+ }
+}
+
+
+/*
* Main "user interface" loop.
*/
void console_app_main(const pj_str_t *uri_to_call)
@@ -1893,6 +1934,44 @@ void console_app_main(const pj_str_t *uri_to_call)
}
break;
+ case 'S':
+ /*
+ * Send arbitrary request
+ */
+ if (pjsua_acc_get_count() == 0) {
+ puts("Sorry, need at least one account configured");
+ break;
+ }
+
+ puts("Send arbitrary request to remote host");
+
+ /* Input METHOD */
+ if (!simple_input("Request method:",text,sizeof(text)))
+ break;
+
+ /* Input destination URI */
+ uri = NULL;
+ ui_input_url("Destination URI", buf, sizeof(buf), &result);
+ if (result.nb_result != NO_NB) {
+
+ if (result.nb_result == -1 || result.nb_result == 0) {
+ puts("Sorry you can't do that!");
+ continue;
+ } else {
+ pjsua_buddy_info binfo;
+ pjsua_buddy_get_info(result.nb_result-1, &binfo);
+ uri = binfo.uri.ptr;
+ }
+
+ } else if (result.uri_result) {
+ uri = result.uri_result;
+ }
+
+ tmp = pj_str(uri);
+
+ send_request(text, &tmp);
+ break;
+
case 's':
case 'u':
/*
diff --git a/pjsip/include/pjsip-simple/evsub.h b/pjsip/include/pjsip-simple/evsub.h
index 4eb2ae1c..e352e798 100644
--- a/pjsip/include/pjsip-simple/evsub.h
+++ b/pjsip/include/pjsip-simple/evsub.h
@@ -252,6 +252,18 @@ PJ_DECL(pj_status_t) pjsip_evsub_register_pkg( pjsip_module *pkg_mod,
unsigned accept_cnt,
const pj_str_t accept[]);
+/**
+ * Get the Allow-Events header. This header is built based on the packages
+ * that are registered to the evsub module.
+ *
+ * @param m Pointer to event subscription module instance, or
+ * NULL to use default instance (equal to
+ * #pjsip_evsub_instance()).
+ *
+ * @return The Allow-Events header.
+ */
+PJ_DECL(const pjsip_hdr*) pjsip_evsub_get_allow_events_hdr(pjsip_module *m);
+
/**
* Create client subscription session.
diff --git a/pjsip/include/pjsip-ua/sip_inv.h b/pjsip/include/pjsip-ua/sip_inv.h
index e07ba79a..cb6dc251 100644
--- a/pjsip/include/pjsip-ua/sip_inv.h
+++ b/pjsip/include/pjsip-ua/sip_inv.h
@@ -615,6 +615,21 @@ PJ_DECL(pjsip_inv_session*) pjsip_tsx_get_inv_session(pjsip_transaction *tsx);
PJ_DECL(const char *) pjsip_inv_state_name(pjsip_inv_state state);
+/**
+ * This is a utility function to create SIP body for SDP content.
+ *
+ * @param pool Pool to allocate memory.
+ * @param sdp SDP session to be put in the SIP message body.
+ * @param p_body Pointer to receive SIP message body containing
+ * the SDP session.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_create_sdp_body(pj_pool_t *pool,
+ pjmedia_sdp_session *sdp,
+ pjsip_msg_body **p_body);
+
+
PJ_END_DECL
/**
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index 7ae37eed..5b8125a2 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -417,6 +417,11 @@ typedef struct pjsua_config
*/
pjsua_callback cb;
+ /**
+ * User agent string (default empty)
+ */
+ pj_str_t user_agent;
+
} pjsua_config;
@@ -468,6 +473,8 @@ PJ_INLINE(void) pjsua_config_dup(pj_pool_t *pool,
for (i=0; i<src->cred_count; ++i) {
pjsip_cred_dup(pool, &dst->cred_info[i], &src->cred_info[i]);
}
+
+ pj_strdup_with_null(pool, &dst->user_agent, &src->user_agent);
}
@@ -2080,7 +2087,7 @@ struct pjsua_media_config
* The media quality also sets speex codec quality/complexity to the
* number.
*
- * Default: 3.
+ * Default: 5.
*/
unsigned quality;
};
@@ -2099,7 +2106,7 @@ PJ_INLINE(void) pjsua_media_config_default(pjsua_media_config *cfg)
cfg->max_media_ports = 32;
cfg->has_ioqueue = PJ_TRUE;
cfg->thread_cnt = 1;
- cfg->quality = 3;
+ cfg->quality = 5;
}
diff --git a/pjsip/src/pjsip-simple/evsub.c b/pjsip/src/pjsip-simple/evsub.c
index 7b13d548..e5b4f526 100644
--- a/pjsip/src/pjsip-simple/evsub.c
+++ b/pjsip/src/pjsip-simple/evsub.c
@@ -420,6 +420,12 @@ PJ_DEF(pj_status_t) pjsip_evsub_register_pkg( pjsip_module *pkg_mod,
++mod_evsub.allow_events_hdr->count;
}
+ /* Add to endpoint's Accept header */
+ pjsip_endpt_add_capability(mod_evsub.endpt, &mod_evsub.mod,
+ PJSIP_H_ACCEPT, NULL,
+ pkg->pkg_accept->count,
+ pkg->pkg_accept->values);
+
/* Done */
@@ -431,6 +437,21 @@ PJ_DEF(pj_status_t) pjsip_evsub_register_pkg( pjsip_module *pkg_mod,
}
+/*
+ * Retrieve Allow-Events header
+ */
+PJ_DEF(const pjsip_hdr*) pjsip_evsub_get_allow_events_hdr(pjsip_module *m)
+{
+ struct mod_evsub *mod;
+
+ if (m == NULL)
+ m = pjsip_evsub_instance();
+
+ mod = (struct mod_evsub*)m;
+
+ return (pjsip_hdr*) mod->allow_events_hdr;
+}
+
/*
* Update expiration time.
diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c
index d3176862..e35f0eea 100644
--- a/pjsip/src/pjsip-ua/sip_inv.c
+++ b/pjsip/src/pjsip-ua/sip_inv.c
@@ -112,11 +112,16 @@ struct tsx_inv_data
static pj_status_t mod_inv_load(pjsip_endpoint *endpt)
{
pj_str_t allowed[] = {{"INVITE", 6}, {"ACK",3}, {"BYE",3}, {"CANCEL",6}};
+ pj_str_t accepted = { "application/sdp", 15 };
/* Register supported methods: INVITE, ACK, BYE, CANCEL */
pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ALLOW, NULL,
PJ_ARRAY_SIZE(allowed), allowed);
+ /* Register "application/sdp" in Accept header */
+ pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ACCEPT, NULL,
+ 1, &accepted);
+
return PJ_SUCCESS;
}
@@ -959,22 +964,43 @@ static int print_sdp(pjsip_msg_body *body, char *buf, pj_size_t len)
return pjmedia_sdp_print(body->data, buf, len);
}
-static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
- const pjmedia_sdp_session *c_sdp)
+
+PJ_DEF(pj_status_t) pjsip_create_sdp_body( pj_pool_t *pool,
+ pjmedia_sdp_session *sdp,
+ pjsip_msg_body **p_body)
{
+ const pj_str_t STR_APPLICATION = { "application", 11};
+ const pj_str_t STR_SDP = { "sdp", 3 };
pjsip_msg_body *body;
-
body = pj_pool_zalloc(pool, sizeof(pjsip_msg_body));
- PJ_ASSERT_RETURN(body != NULL, NULL);
+ PJ_ASSERT_RETURN(body != NULL, PJ_ENOMEM);
- body->content_type.type = pj_str("application");
- body->content_type.subtype = pj_str("sdp");
- body->data = pjmedia_sdp_session_clone(pool, c_sdp);
+ body->content_type.type = STR_APPLICATION;
+ body->content_type.subtype = STR_SDP;
+ body->data = sdp;
body->len = 0;
body->clone_data = &clone_sdp;
body->print_body = &print_sdp;
+ *p_body = body;
+
+ return PJ_SUCCESS;
+}
+
+static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
+ const pjmedia_sdp_session *c_sdp)
+{
+ pjsip_msg_body *body;
+ pj_status_t status;
+
+ status = pjsip_create_sdp_body(pool,
+ pjmedia_sdp_session_clone(pool, c_sdp),
+ &body);
+
+ if (status != PJ_SUCCESS)
+ return NULL;
+
return body;
}
diff --git a/pjsip/src/pjsip/sip_dialog.c b/pjsip/src/pjsip/sip_dialog.c
index 9b59d258..c84cfd20 100644
--- a/pjsip/src/pjsip/sip_dialog.c
+++ b/pjsip/src/pjsip/sip_dialog.c
@@ -1344,8 +1344,9 @@ void pjsip_dlg_on_rx_request( pjsip_dialog *dlg, pjsip_rx_data *rdata )
pjsip_tx_data *tdata;
const pj_str_t reason = { "No session found", 16};
- PJ_LOG(4,(tsx->obj_name, "Incoming request was unhandled by "
- "dialog usages, sending 500 response"));
+ PJ_LOG(4,(tsx->obj_name, "%s was unhandled by "
+ "dialog usages, sending 500 response",
+ pjsip_rx_data_get_info(rdata)));
status = pjsip_dlg_create_response(dlg, rdata, 500, &reason, &tdata);
if (status == PJ_SUCCESS) {
@@ -1457,10 +1458,13 @@ void pjsip_dlg_on_rx_response( pjsip_dialog *dlg, pjsip_rx_data *rdata )
break;
}
+ /* Unhandled response does not necessarily mean error because
+ dialog usages may choose to process the transaction state instead.
if (i==dlg->usage_cnt) {
- PJ_LOG(4,(dlg->obj_name, "%s is unhandled by dialog usages",
+ PJ_LOG(4,(dlg->obj_name, "%s was not claimed by any dialog usages",
pjsip_rx_data_get_info(rdata)));
}
+ */
/* Unlock dialog and dec session, may destroy dialog. */
pjsip_dlg_dec_lock(dlg);
diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c
index 61b4096a..1d5873be 100644
--- a/pjsip/src/pjsua-lib/pjsua_acc.c
+++ b/pjsip/src/pjsua-lib/pjsua_acc.c
@@ -538,8 +538,10 @@ PJ_DEF(pj_status_t) pjsua_acc_set_registration( pjsua_acc_id acc_id,
status = pjsip_regc_unregister(pjsua_var.acc[acc_id].regc, &tdata);
}
- if (status == PJ_SUCCESS)
+ if (status == PJ_SUCCESS) {
+ pjsua_process_msg_data(tdata, NULL);
status = pjsip_regc_send( pjsua_var.acc[acc_id].regc, tdata );
+ }
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to create/send REGISTER",
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index 98480b9a..930543ea 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -129,6 +129,106 @@ static pjsip_module pjsua_msg_logger =
/*****************************************************************************
+ * Another simple module to handle incoming OPTIONS request
+ */
+
+/* Notification on incoming request */
+static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata)
+{
+ pjsip_tx_data *tdata;
+ pjsip_response_addr res_addr;
+ pjmedia_sdp_session *sdp;
+ const pjsip_hdr *cap_hdr;
+ pj_status_t status;
+
+ /* Only want to handle OPTIONS requests */
+ if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,
+ &pjsip_options_method) != 0)
+ {
+ return PJ_FALSE;
+ }
+
+ /* Create basic response. */
+ status = pjsip_endpt_create_response(pjsua_var.endpt, rdata, 200, NULL,
+ &tdata);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Unable to create OPTIONS response", status);
+ return PJ_TRUE;
+ }
+
+ /* Add Allow header */
+ cap_hdr = pjsip_endpt_get_capability(pjsua_var.endpt, PJSIP_H_ALLOW, NULL);
+ if (cap_hdr) {
+ pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_clone(tdata->pool, cap_hdr));
+ }
+
+ /* Add Accept header */
+ cap_hdr = pjsip_endpt_get_capability(pjsua_var.endpt, PJSIP_H_ACCEPT, NULL);
+ if (cap_hdr) {
+ pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_clone(tdata->pool, cap_hdr));
+ }
+
+ /* Add Supported header */
+ cap_hdr = pjsip_endpt_get_capability(pjsua_var.endpt, PJSIP_H_SUPPORTED, NULL);
+ if (cap_hdr) {
+ pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_clone(tdata->pool, cap_hdr));
+ }
+
+ /* Add Allow-Events header from the evsub module */
+ cap_hdr = pjsip_evsub_get_allow_events_hdr(NULL);
+ if (cap_hdr) {
+ pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_clone(tdata->pool, cap_hdr));
+ }
+
+ /* Add User-Agent header */
+ if (pjsua_var.ua_cfg.user_agent.slen) {
+ const pj_str_t USER_AGENT = { "User-Agent", 10};
+ pjsip_hdr *h;
+
+ h = (pjsip_hdr*) pjsip_generic_string_hdr_create(tdata->pool,
+ &USER_AGENT,
+ &pjsua_var.ua_cfg.user_agent);
+ pjsip_msg_add_hdr(tdata->msg, h);
+ }
+
+ /* Add SDP body, using call0's RTP address */
+ status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, tdata->pool, 1,
+ &pjsua_var.calls[0].skinfo, &sdp);
+ if (status == PJ_SUCCESS) {
+ pjsip_create_sdp_body(tdata->pool, sdp, &tdata->msg->body);
+ }
+
+ /* Send response statelessly */
+ pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
+ status = pjsip_endpt_send_response(pjsua_var.endpt, &res_addr, tdata, NULL, NULL);
+ if (status != PJ_SUCCESS)
+ pjsip_tx_data_dec_ref(tdata);
+
+ return PJ_TRUE;
+}
+
+
+/* The module instance. */
+static pjsip_module pjsua_options_handler =
+{
+ NULL, NULL, /* prev, next. */
+ { "mod-pjsua-options", 17 }, /* Name. */
+ -1, /* Id */
+ PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
+ NULL, /* load() */
+ NULL, /* start() */
+ NULL, /* stop() */
+ NULL, /* unload() */
+ &options_on_rx_request, /* on_rx_request() */
+ NULL, /* on_rx_response() */
+ NULL, /* on_tx_request. */
+ NULL, /* on_tx_response() */
+ NULL, /* on_tsx_state() */
+
+};
+
+
+/*****************************************************************************
* These two functions are the main callbacks registered to PJSIP stack
* to receive SIP request and response messages that are outside any
* dialogs and any transactions.
@@ -234,6 +334,12 @@ PJ_DEF(pj_status_t) pjsua_reconfigure_logging(const pjsua_logging_config *cfg)
}
}
+ /* Unregister OPTIONS handler if it's previously registered */
+ if (pjsua_options_handler.id >= 0) {
+ pjsip_endpt_unregister_module(pjsua_var.endpt, &pjsua_options_handler);
+ pjsua_options_handler.id = -1;
+ }
+
/* Unregister msg logging if it's previously registered */
if (pjsua_msg_logger.id >= 0) {
pjsip_endpt_unregister_module(pjsua_var.endpt, &pjsua_msg_logger);
@@ -244,6 +350,8 @@ PJ_DEF(pj_status_t) pjsua_reconfigure_logging(const pjsua_logging_config *cfg)
if (pjsua_var.log_cfg.msg_logging)
pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_msg_logger);
+ /* Register OPTIONS handler */
+ pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_options_handler);
return PJ_SUCCESS;
}
@@ -1024,6 +1132,18 @@ void pjsua_process_msg_data(pjsip_tx_data *tdata,
pj_bool_t allow_body;
const pjsip_hdr *hdr;
+ /* Always add User-Agent */
+ if (pjsua_var.ua_cfg.user_agent.slen &&
+ tdata->msg->type == PJSIP_REQUEST_MSG)
+ {
+ const pj_str_t STR_USER_AGENT = { "User-Agent", 10 };
+ pjsip_hdr *h;
+ h = (pjsip_hdr*)pjsip_generic_string_hdr_create(tdata->pool,
+ &STR_USER_AGENT,
+ &pjsua_var.ua_cfg.user_agent);
+ pjsip_msg_add_hdr(tdata->msg, h);
+ }
+
if (!msg_data)
return;