Index: pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 3365)
+++ pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 3366)
@@ -2334,4 +2334,39 @@
 
     /**
+     * Control the use of SIP outbound feature. SIP outbound is described in
+     * RFC 5626 to enable proxies or registrar to send inbound requests back
+     * to UA using the same connection initiated by the UA for its
+     * registration. This feature is highly useful in NAT-ed deployemtns,
+     * hence it is enabled by default.
+     *
+     * Note: currently SIP outbound can only be used with TCP and TLS
+     * transports. If UDP is used for the registration, the SIP outbound
+     * feature will be silently ignored for the account.
+     *
+     * Default: PJ_TRUE
+     */
+    unsigned	     use_rfc5626;
+
+    /**
+     * Specify SIP outbound (RFC 5626) instance ID to be used by this
+     * application. If empty, an instance ID will be generated based on
+     * the hostname of this agent. If application specifies this parameter, the
+     * value will look like "<urn:uuid:00000000-0000-1000-8000-AABBCCDDEEFF>"
+     * without the doublequote.
+     *
+     * Default: empty
+     */
+    pj_str_t	     rfc5626_instance_id;
+
+    /**
+     * Specify SIP outbound (RFC 5626) registration ID. The default value
+     * is empty, which would cause the library to automatically generate
+     * a suitable value.
+     *
+     * Default: empty
+     */
+    pj_str_t	     rfc5626_reg_id;
+
+    /**
      * Set the interval for periodic keep-alive transmission for this account.
      * If this value is zero, keep-alive will be disabled for this account.
Index: pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 3365)
+++ pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 3366)
@@ -115,5 +115,4 @@
 };
 
-
 /**
  * Account
@@ -129,4 +128,7 @@
     pj_str_t	     user_part;	    /**< User part of local URI.	*/
     pj_str_t	     contact;	    /**< Our Contact header.		*/
+    pj_str_t         reg_contact;   /**< Contact header for REGISTER.
+				         It may be different than acc
+				         contact if outbound is used    */
 
     pj_str_t	     srv_domain;    /**< Host part of reg server.	*/
@@ -152,4 +154,11 @@
     pj_uint32_t	     global_route_crc; /** CRC of global route setting. */
     pj_uint32_t	     local_route_crc;  /** CRC of account route setting.*/
+
+    unsigned         rfc5626_status;/**< SIP outbound status:
+                                           0: not used
+                                           1: requested
+                                           2: acknowledged by servers   */
+    pj_str_t	     rfc5626_instprm;/**< SIP outbound instance param.  */
+    pj_str_t         rfc5626_regprm;/**< SIP outbound reg param.        */
 
     unsigned	     cred_cnt;	    /**< Number of credentials.		*/
Index: pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c	(revision 3365)
+++ pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c	(revision 3366)
@@ -24,4 +24,11 @@
 #define THIS_FILE		"pjsua_acc.c"
 
+enum
+{
+    OUTBOUND_NONE,
+    OUTBOUND_WANTED,
+    OUTBOUND_ACTIVE
+};
+
 
 static void schedule_reregistration(pjsua_acc *acc);
@@ -80,4 +87,6 @@
     pj_strdup_with_null(pool, &dst->force_contact, &src->force_contact);
     pj_strdup_with_null(pool, &dst->pidf_tuple_id, &src->pidf_tuple_id);
+    pj_strdup_with_null(pool, &dst->rfc5626_instance_id, &src->rfc5626_instance_id);
+    pj_strdup_with_null(pool, &dst->rfc5626_reg_id, &src->rfc5626_reg_id);
 
     dst->proxy_cnt = src->proxy_cnt;
@@ -269,4 +278,53 @@
     if (status != PJ_SUCCESS)
 	return status;
+
+    /* If SIP outbound is enabled, generate instance and reg ID if they are
+     * not specified
+     */
+    if (acc_cfg->use_rfc5626) {
+	if (acc_cfg->rfc5626_instance_id.slen==0) {
+	    const pj_str_t *hostname;
+	    pj_uint32_t hval, pos;
+	    char instprm[] = ";+sip.instance=\"<urn:uuid:00000000-0000-0000-0000-0000CCDDEEFF>\"";
+
+	    hostname = pj_gethostname();
+	    pos = pj_ansi_strlen(instprm) - 10;
+	    hval = pj_hash_calc(0, hostname->ptr, hostname->slen);
+	    pj_val_to_hex_digit( ((char*)&hval)[0], instprm+pos+0);
+	    pj_val_to_hex_digit( ((char*)&hval)[1], instprm+pos+2);
+	    pj_val_to_hex_digit( ((char*)&hval)[2], instprm+pos+4);
+	    pj_val_to_hex_digit( ((char*)&hval)[3], instprm+pos+6);
+
+	    pj_strdup2(acc->pool, &acc->rfc5626_instprm, instprm);
+	} else {
+	    const char *prmname = ";+sip.instance=\"";
+	    unsigned len;
+
+	    len = pj_ansi_strlen(prmname) + acc_cfg->rfc5626_instance_id.slen + 1;
+	    acc->rfc5626_instprm.ptr = (char*)pj_pool_alloc(acc->pool, len+1);
+	    pj_ansi_snprintf(acc->rfc5626_instprm.ptr, len+1,
+		             "%s%.*s\"",
+		             prmname,
+		             (int)acc_cfg->rfc5626_instance_id.slen,
+		             acc_cfg->rfc5626_instance_id.ptr);
+	    acc->rfc5626_instprm.slen = len;
+	}
+
+	if (acc_cfg->rfc5626_reg_id.slen==0) {
+	    acc->rfc5626_regprm = pj_str(";reg-id=1");
+	} else {
+	    const char *prmname = ";reg-id=";
+	    unsigned len;
+
+	    len = pj_ansi_strlen(prmname) + acc_cfg->rfc5626_reg_id.slen;
+	    acc->rfc5626_regprm.ptr = (char*)pj_pool_alloc(acc->pool, len+1);
+	    pj_ansi_snprintf(acc->rfc5626_regprm.ptr, len+1,
+		             "%s%.*s\"",
+		             prmname,
+		             (int)acc_cfg->rfc5626_reg_id.slen,
+		             acc_cfg->rfc5626_reg_id.ptr);
+	    acc->rfc5626_regprm.slen = len;
+	}
+    }
 
     /* Mark account as valid */
@@ -900,4 +958,12 @@
     }
 
+    /* SIP outbound setting */
+    if (acc->cfg.use_rfc5626 != cfg->use_rfc5626 ||
+	pj_strcmp(&acc->cfg.rfc5626_instance_id, &cfg->rfc5626_instance_id) ||
+	pj_strcmp(&acc->cfg.rfc5626_reg_id, &cfg->rfc5626_reg_id))
+    {
+	update_reg = PJ_TRUE;
+    }
+
     /* Update registration */
     if (update_reg) {
@@ -954,4 +1020,60 @@
     pjsua_pres_update_acc(acc_id, PJ_TRUE);
     return PJ_SUCCESS;
+}
+
+/* Create reg_contact, mainly for SIP outbound */
+static void update_regc_contact(pjsua_acc *acc)
+{
+    pjsua_acc_config *acc_cfg = &acc->cfg;
+    pj_bool_t need_outbound = PJ_FALSE;
+    const pj_str_t tcp_param = pj_str(";transport=tcp");
+    const pj_str_t tls_param = pj_str(";transport=tls");
+
+    if (!acc_cfg->use_rfc5626)
+	goto done;
+
+    if (pj_stristr(&acc->contact, &tcp_param)==NULL &&
+	pj_stristr(&acc->contact, &tls_param)==NULL)
+    {
+	/* Currently we can only do SIP outbound for TCP
+	 * and TLS.
+	 */
+	goto done;
+    }
+
+    /* looks like we can use outbound */
+    need_outbound = PJ_TRUE;
+
+done:
+    if (!need_outbound) {
+	/* Outbound is not needed/wanted for the account. acc->reg_contact
+	 * is set to the same as acc->contact.
+	 */
+	acc->reg_contact = acc->contact;
+	acc->rfc5626_status = OUTBOUND_NONE;
+    } else {
+	/* Need to use outbound, append the contact with +sip.instance and
+	 * reg-id parameters.
+	 */
+	unsigned len;
+	pj_str_t reg_contact;
+
+	acc->rfc5626_status = OUTBOUND_WANTED;
+	len = acc->contact.slen + acc->rfc5626_instprm.slen +
+	      acc->rfc5626_regprm.slen;
+	reg_contact.ptr = (char*) pj_pool_alloc(acc->pool, reg_contact.slen);
+
+	pj_strcpy(&reg_contact, &acc->contact);
+	pj_strcat(&reg_contact, &acc->rfc5626_regprm);
+	pj_strcat(&reg_contact, &acc->rfc5626_instprm);
+
+	acc->reg_contact = reg_contact;
+
+	PJ_LOG(4,(THIS_FILE,
+		  "Contact for acc %d updated for SIP outbound: %.*s",
+		  acc->index,
+		  (int)acc->reg_contact.slen,
+		  acc->reg_contact.ptr));
+    }
 }
 
@@ -999,4 +1121,11 @@
     if (acc->cfg.allow_contact_rewrite == PJ_FALSE)
 	return PJ_FALSE;
+
+    /* If SIP outbound is active, no need to update */
+    if (acc->rfc5626_status == OUTBOUND_ACTIVE) {
+	PJ_LOG(4,(THIS_FILE, "Acc %d has SIP outbound active, no need to "
+			     "update registration Contact", acc->index));
+	return PJ_FALSE;
+    }
 
 #if 0
@@ -1143,4 +1272,5 @@
      */
     {
+	const char *ob = ";ob";
 	char *tmp;
 	const char *beginquote, *endquote;
@@ -1157,5 +1287,5 @@
 	tmp = (char*) pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
 	len = pj_ansi_snprintf(tmp, PJSIP_MAX_URL_SIZE,
-			       "<sip:%.*s%s%s%.*s%s:%d;transport=%s%.*s>%.*s",
+			       "<sip:%.*s%s%s%.*s%s:%d;transport=%s%.*s%s>%.*s",
 			       (int)acc->user_part.slen,
 			       acc->user_part.ptr,
@@ -1169,4 +1299,5 @@
 			       (int)acc->cfg.contact_uri_params.slen,
 			       acc->cfg.contact_uri_params.ptr,
+			       ob,
 			       (int)acc->cfg.contact_params.slen,
 			       acc->cfg.contact_params.ptr);
@@ -1178,4 +1309,6 @@
 	pj_strdup2_with_null(acc->pool, &acc->contact, tmp);
 
+	update_regc_contact(acc);
+
 	/* Always update, by http://trac.pjsip.org/repos/ticket/864. */
 	pj_strdup_with_null(tp->pool, &tp->local_name.host, via_addr);
@@ -1185,5 +1318,5 @@
 
     if (acc->cfg.contact_rewrite_method == 2 && acc->regc != NULL) {
-	pjsip_regc_update_contact(acc->regc, 1, &acc->contact);
+	pjsip_regc_update_contact(acc->regc, 1, &acc->reg_contact);
     }
 
@@ -1419,4 +1552,37 @@
 
 
+/* Update the status of SIP outbound registration request */
+static void update_rfc5626_status(pjsua_acc *acc, pjsip_rx_data *rdata)
+{
+    pjsip_require_hdr *hreq;
+    const pj_str_t STR_OUTBOUND = {"outbound", 8};
+    unsigned i;
+
+    if (acc->rfc5626_status == OUTBOUND_NONE) {
+	goto on_return;
+    }
+
+    hreq = rdata->msg_info.require;
+    if (!hreq) {
+	acc->rfc5626_status = OUTBOUND_NONE;
+	goto on_return;
+    }
+
+    for (i=0; i<hreq->count; ++i) {
+	if (pj_stricmp(&hreq->values[i], &STR_OUTBOUND)==0) {
+	    acc->rfc5626_status = OUTBOUND_ACTIVE;
+	    goto on_return;
+	}
+    }
+
+    /* Server does not support outbound */
+    acc->rfc5626_status = OUTBOUND_NONE;
+
+on_return:
+    PJ_LOG(4,(THIS_FILE, "SIP outbound status for acc %d is %s",
+			 acc->index, (acc->rfc5626_status==OUTBOUND_ACTIVE?
+					 "active": "not active")));
+}
+
 /*
  * This callback is called by pjsip_regc when outgoing register
@@ -1474,7 +1640,11 @@
 		      pjsua_var.acc[acc->index].cfg.id.ptr));
 	} else {
+	    /* Check and update SIP outbound status first, since the result
+	     * will determine if we should update re-registration
+	     */
+	    update_rfc5626_status(acc, param->rdata);
+
 	    /* Check NAT bound address */
 	    if (acc_check_nat_addr(acc, param)) {
-		/* Update address, don't notify application yet */
 		PJSUA_UNLOCK();
 		return;
@@ -1596,4 +1766,5 @@
 
 	pj_strdup_with_null(acc->pool, &acc->contact, &tmp_contact);
+	update_regc_contact(acc);
     }
 
@@ -1602,5 +1773,5 @@
 			      &acc->cfg.id, 
 			      &acc->cfg.id,
-			      1, &acc->contact, 
+			      1, &acc->reg_contact,
 			      acc->cfg.reg_timeout);
     if (status != PJ_SUCCESS) {
@@ -1683,4 +1854,20 @@
 					    &pjsua_var.ua_cfg.user_agent);
 	pj_list_push_back(&hdr_list, (pjsip_hdr*)h);
+
+	pjsip_regc_add_headers(acc->regc, &hdr_list);
+    }
+
+    /* If SIP outbound is used, add "Supported: outbound, path header" */
+    if (acc->rfc5626_status == OUTBOUND_WANTED) {
+	pjsip_hdr hdr_list;
+	pjsip_supported_hdr *hsup;
+
+	pj_list_init(&hdr_list);
+	hsup = pjsip_supported_hdr_create(pool);
+	pj_list_push_back(&hdr_list, hsup);
+
+	hsup->count = 2;
+	hsup->values[0] = pj_str("outbound");
+	hsup->values[1] = pj_str("path");
 
 	pjsip_regc_add_headers(acc->regc, &hdr_list);
@@ -2147,4 +2334,5 @@
     const char *beginquote, *endquote;
     char transport_param[32];
+    const char *ob = ";ob";
 
     
@@ -2232,5 +2420,5 @@
     contact->ptr = (char*)pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
     contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
-				     "%.*s%s<%s:%.*s%s%s%.*s%s:%d%s%.*s>%.*s",
+				     "%.*s%s<%s:%.*s%s%s%.*s%s:%d%s%.*s%s>%.*s",
 				     (int)acc->display.slen,
 				     acc->display.ptr,
@@ -2248,4 +2436,5 @@
 				     (int)acc->cfg.contact_uri_params.slen,
 				     acc->cfg.contact_uri_params.ptr,
+				     ob,
 				     (int)acc->cfg.contact_params.slen,
 				     acc->cfg.contact_params.ptr);
Index: pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 3365)
+++ pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 3366)
@@ -184,4 +184,5 @@
     cfg->reg_retry_interval = PJSUA_REG_RETRY_INTERVAL;
     cfg->contact_rewrite_method = PJSUA_CONTACT_REWRITE_METHOD;
+    cfg->use_rfc5626 = PJ_TRUE;
     cfg->reg_use_proxy = PJSUA_REG_USE_OUTBOUND_PROXY |
 			 PJSUA_REG_USE_ACC_PROXY;
