summaryrefslogtreecommitdiff
path: root/pjsip
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-10-31 13:28:08 +0000
committerBenny Prijono <bennylp@teluu.com>2007-10-31 13:28:08 +0000
commitef040a9c543b0b51e0f278ebb7a3e6a9588e9b83 (patch)
tree48055d526b8ebf7c313fe7a61cfd101c528e5e8c /pjsip
parentc25863d18e273d92f61550f7dccf9a54c81dd9b8 (diff)
Ticket #407: keep-alive for UDP transports in PJSUA-LIB
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1536 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip')
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h38
-rw-r--r--pjsip/include/pjsua-lib/pjsua_internal.h6
-rw-r--r--pjsip/src/pjsip/sip_transport.c8
-rw-r--r--pjsip/src/pjsua-lib/pjsua_acc.c141
-rw-r--r--pjsip/src/pjsua-lib/pjsua_core.c2
5 files changed, 185 insertions, 10 deletions
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index 579d722f..fb324f4d 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -1768,7 +1768,7 @@ PJ_DECL(pj_status_t) pjsua_transport_close( pjsua_transport_id id,
* Default registration interval.
*/
#ifndef PJSUA_REG_INTERVAL
-# define PJSUA_REG_INTERVAL 55
+# define PJSUA_REG_INTERVAL 300
#endif
@@ -1897,7 +1897,7 @@ typedef struct pjsua_acc_config
/**
* Optional interval for registration, in seconds. If the value is zero,
- * default interval will be used (PJSUA_REG_INTERVAL, 55 seconds).
+ * default interval will be used (PJSUA_REG_INTERVAL, 300 seconds).
*/
unsigned reg_timeout;
@@ -1947,6 +1947,28 @@ typedef struct pjsua_acc_config
*/
pj_bool_t auto_update_nat;
+ /**
+ * Set the interval for periodic keep-alive transmission for this account.
+ * If this value is zero, keep-alive will be disabled for this account.
+ * The keep-alive transmission will be sent to the registrar's address,
+ * after successful registration.
+ *
+ * Even if this setting is enabled, keep-alive transmission is only done
+ * when STUN is enabled in the global #pjsua_config, and the transport
+ * used for registration is UDP. For TCP and TLS transports, keep-alive
+ * is done by the transport themselves.
+ *
+ * Default: 15 (seconds)
+ */
+ unsigned ka_interval;
+
+ /**
+ * Specify the data to be transmitted as keep-alive packets.
+ *
+ * Default: CR-LF
+ */
+ pj_str_t ka_data;
+
} pjsua_acc_config;
@@ -1966,6 +1988,18 @@ PJ_DECL(void) pjsua_acc_config_default(pjsua_acc_config *cfg);
/**
+ * Duplicate account config.
+ *
+ * @param pool Pool to be used for duplicating the config.
+ * @param dst Destination configuration.
+ * @param src Source configuration.
+ */
+PJ_DECL(void) pjsua_acc_config_dup(pj_pool_t *pool,
+ pjsua_acc_config *dst,
+ const pjsua_acc_config *src);
+
+
+/**
* Account info. Application can query account info by calling
* #pjsua_acc_get_info().
*
diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h
index 004c1ca1..87d30b99 100644
--- a/pjsip/include/pjsua-lib/pjsua_internal.h
+++ b/pjsip/include/pjsua-lib/pjsua_internal.h
@@ -86,10 +86,14 @@ typedef struct pjsua_acc
int srv_port; /**< Port number of reg server. */
pjsip_regc *regc; /**< Client registration session. */
- pj_timer_entry reg_timer; /**< Registration timer. */
pj_status_t reg_last_err; /**< Last registration error. */
int reg_last_code; /**< Last status last register. */
+ pj_timer_entry ka_timer; /**< Keep-alive timer for UDP. */
+ pjsip_transport *ka_transport; /**< Transport for keep-alive. */
+ pj_sockaddr ka_target; /**< Destination address for K-A */
+ unsigned ka_target_len; /**< Length of ka_target. */
+
pjsip_route_hdr route_set; /**< Complete route set inc. outbnd.*/
unsigned cred_cnt; /**< Number of credentials. */
diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c
index 1ac9f6ff..11191c54 100644
--- a/pjsip/src/pjsip/sip_transport.c
+++ b/pjsip/src/pjsip/sip_transport.c
@@ -417,12 +417,12 @@ static char *get_msg_info(pj_pool_t *pool, const char *obj_name,
PJ_DEF(char*) pjsip_tx_data_get_info( pjsip_tx_data *tdata )
{
- if (tdata==NULL || tdata->msg==NULL)
- return "NULL";
-
if (tdata->info)
return tdata->info;
+ if (tdata==NULL || tdata->msg==NULL)
+ return "NULL";
+
pj_lock_acquire(tdata->lock);
tdata->info = get_msg_info(tdata->pool, tdata->obj_name, tdata->msg);
pj_lock_release(tdata->lock);
@@ -653,6 +653,8 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_send_raw(pjsip_tpmgr *mgr,
return status;
}
+ tdata->info = "raw";
+
/* Add reference counter. */
pjsip_tx_data_add_ref(tdata);
}
diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c
index 012832c5..a935300e 100644
--- a/pjsip/src/pjsua-lib/pjsua_acc.c
+++ b/pjsip/src/pjsua-lib/pjsua_acc.c
@@ -64,9 +64,9 @@ PJ_DEF(pjsua_acc_id) pjsua_acc_get_default(void)
/*
* Copy account configuration.
*/
-static void copy_acc_config(pj_pool_t *pool,
- pjsua_acc_config *dst,
- const pjsua_acc_config *src)
+PJ_DEF(void) pjsua_acc_config_dup( pj_pool_t *pool,
+ pjsua_acc_config *dst,
+ const pjsua_acc_config *src)
{
unsigned i;
@@ -87,6 +87,9 @@ static void copy_acc_config(pj_pool_t *pool,
for (i=0; i<src->cred_count; ++i) {
pjsip_cred_dup(pool, &dst->cred_info[i], &src->cred_info[i]);
}
+
+ dst->ka_interval = src->ka_interval;
+ pj_strdup(pool, &dst->ka_data, &src->ka_data);
}
@@ -275,7 +278,7 @@ PJ_DEF(pj_status_t) pjsua_acc_add( const pjsua_acc_config *cfg,
{PJSUA_UNLOCK(); return PJ_EBUG;});
/* Copy config */
- copy_acc_config(pjsua_var.pool, &pjsua_var.acc[id].cfg, cfg);
+ pjsua_acc_config_dup(pjsua_var.pool, &pjsua_var.acc[id].cfg, cfg);
/* Normalize registration timeout */
if (pjsua_var.acc[id].cfg.reg_uri.slen &&
@@ -631,6 +634,123 @@ void update_service_route(pjsua_acc *acc, pjsip_rx_data *rdata)
acc->index, uri_cnt));
}
+
+/* Keep alive timer callback */
+static void keep_alive_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te)
+{
+ pjsua_acc *acc;
+ pjsip_tpselector tp_sel;
+ pj_time_val delay;
+ pj_status_t status;
+
+ PJ_UNUSED_ARG(th);
+
+ PJSUA_LOCK();
+
+ te->id = PJ_FALSE;
+
+ acc = (pjsua_acc*) te->user_data;
+
+ /* Select the transport to send the packet */
+ pj_bzero(&tp_sel, sizeof(tp_sel));
+ tp_sel.type = PJSIP_TPSELECTOR_TRANSPORT;
+ tp_sel.u.transport = acc->ka_transport;
+
+ PJ_LOG(5,(THIS_FILE,
+ "Sending %d bytes keep-alive packet for acc %d to %s:%d",
+ acc->cfg.ka_data.slen, acc->index,
+ pj_inet_ntoa(acc->ka_target.ipv4.sin_addr),
+ pj_ntohs(acc->ka_target.ipv4.sin_port)));
+
+ /* Send raw packet */
+ status = pjsip_tpmgr_send_raw(pjsip_endpt_get_tpmgr(pjsua_var.endpt),
+ PJSIP_TRANSPORT_UDP, &tp_sel,
+ NULL, acc->cfg.ka_data.ptr,
+ acc->cfg.ka_data.slen,
+ &acc->ka_target, acc->ka_target_len,
+ NULL, NULL);
+
+ if (status != PJ_SUCCESS && status != PJ_EPENDING) {
+ pjsua_perror(THIS_FILE, "Error sending keep-alive packet", status);
+ }
+
+ /* Reschedule next timer */
+ delay.sec = acc->cfg.ka_interval;
+ delay.msec = 0;
+ status = pjsip_endpt_schedule_timer(pjsua_var.endpt, te, &delay);
+ if (status == PJ_SUCCESS) {
+ te->id = PJ_TRUE;
+ } else {
+ pjsua_perror(THIS_FILE, "Error starting keep-alive timer", status);
+ }
+
+ PJSUA_UNLOCK();
+}
+
+
+/* Update keep-alive for the account */
+static void update_keep_alive(pjsua_acc *acc, pj_bool_t start,
+ struct pjsip_regc_cbparam *param)
+{
+ /* In all cases, stop keep-alive timer if it's running. */
+ if (acc->ka_timer.id) {
+ pjsip_endpt_cancel_timer(pjsua_var.endpt, &acc->ka_timer);
+ acc->ka_timer.id = PJ_FALSE;
+
+ pjsip_transport_dec_ref(acc->ka_transport);
+ acc->ka_transport = NULL;
+ }
+
+ if (start) {
+ pj_time_val delay;
+ pj_status_t status;
+
+ /* Only do keep-alive if:
+ * - STUN is enabled in global config, and
+ * - ka_interval is not zero in the account, and
+ * - transport is UDP.
+ */
+ if (pjsua_var.stun_srv.ipv4.sin_family == 0 ||
+ acc->cfg.ka_interval == 0 ||
+ param->rdata->tp_info.transport->key.type != PJSIP_TRANSPORT_UDP)
+ {
+ /* Keep alive is not necessary */
+ return;
+ }
+
+ /* Save transport and destination address. */
+ acc->ka_transport = param->rdata->tp_info.transport;
+ pjsip_transport_add_ref(acc->ka_transport);
+ pj_memcpy(&acc->ka_target, &param->rdata->pkt_info.src_addr,
+ param->rdata->pkt_info.src_addr_len);
+ acc->ka_target_len = param->rdata->pkt_info.src_addr_len;
+
+ /* Setup and start the timer */
+ acc->ka_timer.cb = &keep_alive_timer_cb;
+ acc->ka_timer.user_data = (void*)acc;
+
+ delay.sec = acc->cfg.ka_interval;
+ delay.msec = 0;
+ status = pjsip_endpt_schedule_timer(pjsua_var.endpt, &acc->ka_timer,
+ &delay);
+ if (status == PJ_SUCCESS) {
+ acc->ka_timer.id = PJ_TRUE;
+ PJ_LOG(4,(THIS_FILE, "Keep-alive timer started for acc %d, "
+ "destination:%s:%d, interval:%ds",
+ acc->index,
+ param->rdata->pkt_info.src_name,
+ param->rdata->pkt_info.src_port,
+ acc->cfg.ka_interval));
+ } else {
+ acc->ka_timer.id = PJ_FALSE;
+ pjsip_transport_dec_ref(acc->ka_transport);
+ acc->ka_transport = NULL;
+ pjsua_perror(THIS_FILE, "Error starting keep-alive timer", status);
+ }
+ }
+}
+
+
/*
* This callback is called by pjsip_regc when outgoing register
* request has completed.
@@ -654,6 +774,9 @@ static void regc_cb(struct pjsip_regc_cbparam *param)
pjsip_regc_destroy(acc->regc);
acc->regc = NULL;
+ /* Stop keep-alive timer if any. */
+ update_keep_alive(acc, PJ_FALSE, NULL);
+
} else if (param->code < 0 || param->code >= 300) {
PJ_LOG(2, (THIS_FILE, "SIP registration failed, status=%d (%.*s)",
param->code,
@@ -661,11 +784,18 @@ static void regc_cb(struct pjsip_regc_cbparam *param)
pjsip_regc_destroy(acc->regc);
acc->regc = NULL;
+ /* Stop keep-alive timer if any. */
+ update_keep_alive(acc, PJ_FALSE, NULL);
+
} else if (PJSIP_IS_STATUS_IN_CLASS(param->code, 200)) {
if (param->expiration < 1) {
pjsip_regc_destroy(acc->regc);
acc->regc = NULL;
+
+ /* Stop keep-alive timer if any. */
+ update_keep_alive(acc, PJ_FALSE, NULL);
+
PJ_LOG(3,(THIS_FILE, "%s: unregistration success",
pjsua_var.acc[acc->index].cfg.id.ptr));
} else {
@@ -687,6 +817,9 @@ static void regc_cb(struct pjsip_regc_cbparam *param)
(int)param->reason.slen, param->reason.ptr,
param->expiration));
+ /* Start keep-alive timer if necessary. */
+ update_keep_alive(acc, PJ_TRUE, param);
+
/* Send initial PUBLISH if it is enabled */
if (acc->cfg.publish_enabled && acc->publish_sess==NULL)
pjsua_pres_init_publish_acc(acc->index);
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index 2cfca8d9..472df637 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -140,6 +140,8 @@ PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg)
cfg->transport_id = PJSUA_INVALID_ID;
cfg->auto_update_nat = PJ_TRUE;
cfg->require_100rel = pjsua_var.ua_cfg.require_100rel;
+ cfg->ka_interval = 15;
+ cfg->ka_data = pj_str("\r\n");
}
PJ_DEF(void) pjsua_buddy_config_default(pjsua_buddy_config *cfg)