summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-07-18 14:39:40 +0000
committerBenny Prijono <bennylp@teluu.com>2006-07-18 14:39:40 +0000
commit490bd78f06ea0c101244760b2a5bbb1dae1b3041 (patch)
treee676089d77bd8ff0e0748e4666b3f6b21fb1e2b6
parent65035358b4b7f51b4183a0937e9e93ff130d7525 (diff)
Small improvements: (1) pjsua now responds to incoming OPTIONS request, which means that some modules (evsub, invite) need to register their capabilities to the endpoint, (2) added command in pjsua to send arbitrary request
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@612 74dad513-b988-da41-8d7b-12977e46ad98
-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;