Ticket #518: some fixes for growing memory usage in PJSUA-LIB, by using temporary pools for temporary variables and by having separate pool for each account and buddy

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@2130 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c
index ac6d617..008c439 100644
--- a/pjsip/src/pjsua-lib/pjsua_acc.c
+++ b/pjsip/src/pjsua-lib/pjsua_acc.c
@@ -108,7 +108,7 @@
     /* Need to parse local_uri to get the elements: */
 
     name_addr = (pjsip_name_addr*)
-		    pjsip_parse_uri(pjsua_var.pool, acc_cfg->id.ptr,
+		    pjsip_parse_uri(acc->pool, acc_cfg->id.ptr,
 				    acc_cfg->id.slen, 
 				    PJSIP_PARSE_URI_AS_NAMEADDR);
     if (name_addr == NULL) {
@@ -136,7 +136,7 @@
     if (acc_cfg->reg_uri.slen) {
 	pjsip_uri *reg_uri;
 
-	reg_uri = pjsip_parse_uri(pjsua_var.pool, acc_cfg->reg_uri.ptr,
+	reg_uri = pjsip_parse_uri(acc->pool, acc_cfg->reg_uri.ptr,
 				  acc_cfg->reg_uri.slen, 0);
 	if (reg_uri == NULL) {
 	    pjsua_perror(THIS_FILE, "Invalid registrar URI", 
@@ -187,10 +187,10 @@
 	pjsip_route_hdr *r;
 	pj_str_t tmp;
 
-	pj_strdup_with_null(pjsua_var.pool, &tmp, 
+	pj_strdup_with_null(acc->pool, &tmp, 
 			    &pjsua_var.ua_cfg.outbound_proxy[i]);
 	r = (pjsip_route_hdr*)
-	    pjsip_parse_hdr(pjsua_var.pool, &hname, tmp.ptr, tmp.slen, NULL);
+	    pjsip_parse_hdr(acc->pool, &hname, tmp.ptr, tmp.slen, NULL);
 	if (r == NULL) {
 	    pjsua_perror(THIS_FILE, "Invalid outbound proxy URI",
 			 PJSIP_EINVALIDURI);
@@ -204,9 +204,9 @@
 	pjsip_route_hdr *r;
 	pj_str_t tmp;
 
-	pj_strdup_with_null(pjsua_var.pool, &tmp, &acc_cfg->proxy[i]);
+	pj_strdup_with_null(acc->pool, &tmp, &acc_cfg->proxy[i]);
 	r = (pjsip_route_hdr*)
-	    pjsip_parse_hdr(pjsua_var.pool, &hname, tmp.ptr, tmp.slen, NULL);
+	    pjsip_parse_hdr(acc->pool, &hname, tmp.ptr, tmp.slen, NULL);
 	if (r == NULL) {
 	    pjsua_perror(THIS_FILE, "Invalid URI in account route set",
 			 PJ_EINVAL);
@@ -256,6 +256,7 @@
 				   pj_bool_t is_default,
 				   pjsua_acc_id *p_acc_id)
 {
+    pjsua_acc *acc;
     unsigned id;
     pj_status_t status;
 
@@ -277,8 +278,16 @@
     PJ_ASSERT_ON_FAIL(	id < PJ_ARRAY_SIZE(pjsua_var.acc), 
 			{PJSUA_UNLOCK(); return PJ_EBUG;});
 
+    acc = &pjsua_var.acc[id];
+
+    /* Create pool for this account. */
+    if (acc->pool)
+	pj_pool_reset(acc->pool);
+    else
+	acc->pool = pjsua_pool_create("acc%p", 512, 256);
+
     /* Copy config */
-    pjsua_acc_config_dup(pjsua_var.pool, &pjsua_var.acc[id].cfg, cfg);
+    pjsua_acc_config_dup(acc->pool, &pjsua_var.acc[id].cfg, cfg);
     
     /* Normalize registration timeout */
     if (pjsua_var.acc[id].cfg.reg_uri.slen &&
@@ -290,6 +299,8 @@
     status = initialize_acc(id);
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Error adding account", status);
+	pj_pool_release(acc->pool);
+	acc->pool = NULL;
 	PJSUA_UNLOCK();
 	return status;
     }
@@ -399,6 +410,12 @@
     /* Delete server presence subscription */
     pjsua_pres_delete_acc(acc_id);
 
+    /* Release account pool */
+    if (pjsua_var.acc[acc_id].pool) {
+	pj_pool_release(pjsua_var.acc[acc_id].pool);
+	pjsua_var.acc[acc_id].pool = NULL;
+    }
+
     /* Invalidate */
     pjsua_var.acc[acc_id].valid = PJ_FALSE;
 
@@ -471,8 +488,11 @@
 		     PJ_EINVAL);
     PJ_ASSERT_RETURN(pjsua_var.acc[acc_id].valid, PJ_EINVALIDOP);
 
+    PJSUA_LOCK();
     pjsua_var.acc[acc_id].online_status = is_online;
-    pjrpid_element_dup(pjsua_var.pool, &pjsua_var.acc[acc_id].rpid, pr);
+    pjrpid_element_dup(pjsua_var.acc[acc_id].pool, &pjsua_var.acc[acc_id].rpid, pr);
+    PJSUA_UNLOCK();
+
     pjsua_pres_update_acc(acc_id, PJ_TRUE);
     return PJ_SUCCESS;
 }
@@ -594,7 +614,7 @@
 	    pj_pool_release(pool);
 	    return PJ_FALSE;
 	}
-	pj_strdup2(pjsua_var.pool, &acc->contact, tmp);
+	pj_strdup2(acc->pool, &acc->contact, tmp);
     }
 
     /* For UDP transport, if STUN is enabled then update the transport's
@@ -702,8 +722,8 @@
 
     /* Then append the Service-Route URIs */
     for (i=0; i<uri_cnt; ++i) {
-	hr = pjsip_route_hdr_create(pjsua_var.pool);
-	hr->name_addr.uri = (pjsip_uri*)pjsip_uri_clone(pjsua_var.pool, uri[i]);
+	hr = pjsip_route_hdr_create(acc->pool);
+	hr->name_addr.uri = (pjsip_uri*)pjsip_uri_clone(acc->pool, uri[i]);
 	pj_list_push_back(&acc->route_set, hr);
     }
 
@@ -982,7 +1002,7 @@
 	    return status;
 	}
 
-	pj_strdup_with_null(pjsua_var.pool, &acc->contact, &tmp_contact);
+	pj_strdup_with_null(acc->pool, &acc->contact, &tmp_contact);
     }
 
     status = pjsip_regc_init( acc->regc,
@@ -1267,16 +1287,18 @@
     pj_str_t tmp;
     pjsip_uri *uri;
     pjsip_sip_uri *sip_uri;
+    pj_pool_t *tmp_pool;
     unsigned i;
 
     PJSUA_LOCK();
 
-    PJ_TODO(dont_use_pjsua_pool);
+    tmp_pool = pjsua_pool_create("tmpacc10", 256, 256);
 
-    pj_strdup_with_null(pjsua_var.pool, &tmp, url);
+    pj_strdup_with_null(tmp_pool, &tmp, url);
 
-    uri = pjsip_parse_uri(pjsua_var.pool, tmp.ptr, tmp.slen, 0);
+    uri = pjsip_parse_uri(tmp_pool, tmp.ptr, tmp.slen, 0);
     if (!uri) {
+	pj_pool_release(tmp_pool);
 	PJSUA_UNLOCK();
 	return pjsua_var.default_acc;
     }
@@ -1294,11 +1316,13 @@
 
 	if (i != PJ_ARRAY_SIZE(pjsua_var.acc)) {
 	    /* Found rather matching account */
+	    pj_pool_release(tmp_pool);
 	    PJSUA_UNLOCK();
-	    return 0;
+	    return i;
 	}
 
 	/* Not found, use default account */
+	pj_pool_release(tmp_pool);
 	PJSUA_UNLOCK();
 	return pjsua_var.default_acc;
     }
@@ -1311,6 +1335,7 @@
 	if (pj_stricmp(&pjsua_var.acc[acc_id].srv_domain, &sip_uri->host)==0 &&
 	    pjsua_var.acc[acc_id].srv_port == sip_uri->port)
 	{
+	    pj_pool_release(tmp_pool);
 	    PJSUA_UNLOCK();
 	    return acc_id;
 	}
@@ -1321,6 +1346,7 @@
 	unsigned acc_id = pjsua_var.acc_ids[i];
 	if (pj_stricmp(&pjsua_var.acc[acc_id].srv_domain, &sip_uri->host)==0)
 	{
+	    pj_pool_release(tmp_pool);
 	    PJSUA_UNLOCK();
 	    return acc_id;
 	}
@@ -1328,6 +1354,7 @@
 
 
     /* Still no match, just use default account */
+    pj_pool_release(tmp_pool);
     PJSUA_UNLOCK();
     return pjsua_var.default_acc;
 }
diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c
index f493c9d..f3424a6 100644
--- a/pjsip/src/pjsua-lib/pjsua_call.c
+++ b/pjsip/src/pjsua-lib/pjsua_call.c
@@ -330,6 +330,7 @@
 					  const pjsua_msg_data *msg_data,
 					  pjsua_call_id *p_call_id)
 {
+    pj_pool_t *tmp_pool;
     pjsip_dialog *dlg = NULL;
     pjmedia_sdp_session *offer;
     pjsip_inv_session *inv = NULL;
@@ -382,30 +383,25 @@
 
     call = &pjsua_var.calls[call_id];
 
+    /* Create temporary pool */
+    tmp_pool = pjsua_pool_create("tmpcall10", 512, 256);
+
     /* Verify that destination URI is valid before calling 
      * pjsua_acc_create_uac_contact, or otherwise there  
      * a misleading "Invalid Contact URI" error will be printed
      * when pjsua_acc_create_uac_contact() fails.
      */
     if (1) {
-	pj_pool_t *pool;
 	pjsip_uri *uri;
 	pj_str_t dup;
 
-	pool = pjsua_pool_create("tmp-uri", 4000, 4000);
-	if (!pool) {
-	    pjsua_perror(THIS_FILE, "Unable to create pool", PJ_ENOMEM);
-	    PJSUA_UNLOCK();
-	    return PJ_ENOMEM;
-	}
-	
-	pj_strdup_with_null(pool, &dup, dest_uri);
-	uri = pjsip_parse_uri(pool, dup.ptr, dup.slen, 0);
-	pj_pool_release(pool);
+	pj_strdup_with_null(tmp_pool, &dup, dest_uri);
+	uri = pjsip_parse_uri(tmp_pool, dup.ptr, dup.slen, 0);
 
 	if (uri == NULL) {
 	    pjsua_perror(THIS_FILE, "Unable to make call", 
 			 PJSIP_EINVALIDREQURI);
+	    pj_pool_release(tmp_pool);
 	    PJSUA_UNLOCK();
 	    return PJSIP_EINVALIDREQURI;
 	}
@@ -426,11 +422,12 @@
     if (acc->contact.slen) {
 	contact = acc->contact;
     } else {
-	status = pjsua_acc_create_uac_contact(pjsua_var.pool, &contact,
+	status = pjsua_acc_create_uac_contact(tmp_pool, &contact,
 					      acc_id, dest_uri);
 	if (status != PJ_SUCCESS) {
 	    pjsua_perror(THIS_FILE, "Unable to generate Contact header", 
 			 status);
+	    pj_pool_release(tmp_pool);
 	    PJSUA_UNLOCK();
 	    return status;
 	}
@@ -442,6 +439,7 @@
 				   dest_uri, dest_uri, &dlg);
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Dialog creation failed", status);
+	pj_pool_release(tmp_pool);
 	PJSUA_UNLOCK();
 	return status;
     }
@@ -549,6 +547,7 @@
     if (p_call_id)
 	*p_call_id = call_id;
 
+    pj_pool_release(tmp_pool);
     PJSUA_UNLOCK();
 
     return PJ_SUCCESS;
@@ -566,6 +565,7 @@
 	pjsua_media_channel_deinit(call_id);
     }
 
+    pj_pool_release(tmp_pool);
     PJSUA_UNLOCK();
     return status;
 }
@@ -2617,17 +2617,21 @@
 				       pjmedia_sdp_session **p_answer)
 {
     pj_status_t status;
+    pj_pool_t *pool;
     pjmedia_sdp_conn *conn;
     pjmedia_sdp_attr *attr;
     pjmedia_transport_info tp_info;
     pjmedia_sdp_session *sdp;
 
+    /* Use call's pool */
+    pool = call->inv->pool;
+
     /* Get media socket info */
     pjmedia_transport_info_init(&tp_info);
     pjmedia_transport_get_info(call->med_tp, &tp_info);
 
     /* Create new offer */
-    status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, pjsua_var.pool, 1,
+    status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, pool, 1,
 				      &tp_info.sock_info, &sdp);
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
@@ -2649,7 +2653,7 @@
     pjmedia_sdp_media_remove_all_attr(sdp->media[0], "inactive");
 
     /* Add inactive attribute */
-    attr = pjmedia_sdp_attr_create(pjsua_var.pool, "inactive", NULL);
+    attr = pjmedia_sdp_attr_create(pool, "inactive", NULL);
     pjmedia_sdp_media_add_attr(sdp->media[0], attr);
 
     *p_answer = sdp;
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index 0bee539..bc26f62 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -580,7 +580,7 @@
     pj_caching_pool_init(&pjsua_var.cp, NULL, 0);
 
     /* Create memory pool for application. */
-    pjsua_var.pool = pjsua_pool_create("pjsua", 4000, 4000);
+    pjsua_var.pool = pjsua_pool_create("pjsua", 1000, 1000);
     
     PJ_ASSERT_RETURN(pjsua_var.pool, PJ_ENOMEM);
 
@@ -1069,7 +1069,15 @@
 	/* Terminate all presence subscriptions. */
 	pjsua_pres_shutdown();
 
-	/* Unregister, if required: */
+	/* Destroy pool in the buddy object */
+	for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) {
+	    if (pjsua_var.buddy[i].pool) {
+		pj_pool_release(pjsua_var.buddy[i].pool);
+		pjsua_var.buddy[i].pool = NULL;
+	    }
+	}
+
+	/* Destroy accounts */
 	for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
 	    if (!pjsua_var.acc[i].valid)
 		continue;
@@ -1077,6 +1085,11 @@
 	    if (pjsua_var.acc[i].regc) {
 		pjsua_acc_set_registration(i, PJ_FALSE);
 	    }
+
+	    if (pjsua_var.acc[i].pool) {
+		pj_pool_release(pjsua_var.acc[i].pool);
+		pjsua_var.acc[i].pool = NULL;
+	    }
 	}
 
 	/* Wait for some time to allow unregistration to complete: */
diff --git a/pjsip/src/pjsua-lib/pjsua_pres.c b/pjsip/src/pjsua-lib/pjsua_pres.c
index c7a3ffc..e1d7111 100644
--- a/pjsip/src/pjsua-lib/pjsua_pres.c
+++ b/pjsip/src/pjsua-lib/pjsua_pres.c
@@ -173,7 +173,9 @@
  */
 static void reset_buddy(pjsua_buddy_id id)
 {
+    pj_pool_t *pool = pjsua_var.buddy[id].pool;
     pj_bzero(&pjsua_var.buddy[id], sizeof(pjsua_var.buddy[id]));
+    pjsua_var.buddy[id].pool = pool;
     pjsua_var.buddy[id].index = id;
 }
 
@@ -185,6 +187,7 @@
 				     pjsua_buddy_id *p_buddy_id)
 {
     pjsip_name_addr *url;
+    pjsua_buddy *buddy;
     pjsip_sip_uri *sip_uri;
     int index;
     pj_str_t tmp;
@@ -209,21 +212,37 @@
 	return PJ_ETOOMANY;
     }
 
+    buddy = &pjsua_var.buddy[index];
+
+    /* Create pool for this buddy */
+    if (buddy->pool) {
+	pj_pool_reset(buddy->pool);
+    } else {
+	char name[PJ_MAX_OBJ_NAME];
+	pj_ansi_snprintf(name, sizeof(name), "buddy%03d", index);
+	buddy->pool = pjsua_pool_create(name, 512, 256);
+    }
 
     /* Get name and display name for buddy */
-    pj_strdup_with_null(pjsua_var.pool, &tmp, &cfg->uri);
-    url = (pjsip_name_addr*)pjsip_parse_uri(pjsua_var.pool, tmp.ptr, tmp.slen,
+    pj_strdup_with_null(buddy->pool, &tmp, &cfg->uri);
+    url = (pjsip_name_addr*)pjsip_parse_uri(buddy->pool, tmp.ptr, tmp.slen,
 					    PJSIP_PARSE_URI_AS_NAMEADDR);
 
     if (url == NULL) {
 	pjsua_perror(THIS_FILE, "Unable to add buddy", PJSIP_EINVALIDURI);
+	pj_pool_release(buddy->pool);
+	buddy->pool = NULL;
 	PJSUA_UNLOCK();
 	return PJSIP_EINVALIDURI;
     }
 
     /* Only support SIP schemes */
-    if (!PJSIP_URI_SCHEME_IS_SIP(url) && !PJSIP_URI_SCHEME_IS_SIPS(url))
+    if (!PJSIP_URI_SCHEME_IS_SIP(url) && !PJSIP_URI_SCHEME_IS_SIPS(url)) {
+	pj_pool_release(buddy->pool);
+	buddy->pool = NULL;
+	PJSUA_UNLOCK();
 	return PJSIP_EINVALIDSCHEME;
+    }
 
     /* Reset buddy, to make sure everything is cleared with default
      * values
@@ -1049,7 +1068,7 @@
     }
 
     buddy->contact.ptr = (char*)
-			 pj_pool_alloc(pjsua_var.pool, PJSIP_MAX_URL_SIZE);
+			 pj_pool_alloc(buddy->pool, PJSIP_MAX_URL_SIZE);
     buddy->contact.slen = pjsip_uri_print( PJSIP_URI_IN_CONTACT_HDR,
 					   contact_hdr->uri,
 					   buddy->contact.ptr, 
@@ -1116,6 +1135,7 @@
 /* It does what it says.. */
 static void subscribe_buddy_presence(unsigned index)
 {
+    pj_pool_t *tmp_pool = NULL;
     pjsua_buddy *buddy;
     int acc_id;
     pjsua_acc *acc;
@@ -1137,11 +1157,14 @@
     if (acc->contact.slen) {
 	contact = acc->contact;
     } else {
-	status = pjsua_acc_create_uac_contact(pjsua_var.pool, &contact,
+	tmp_pool = pjsua_pool_create("tmpbuddy", 512, 256);
+
+	status = pjsua_acc_create_uac_contact(tmp_pool, &contact,
 					      acc_id, &buddy->uri);
 	if (status != PJ_SUCCESS) {
 	    pjsua_perror(THIS_FILE, "Unable to generate Contact header", 
 		         status);
+	    pj_pool_release(tmp_pool);
 	    return;
 	}
     }
@@ -1155,6 +1178,7 @@
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Unable to create dialog", 
 		     status);
+	if (tmp_pool) pj_pool_release(tmp_pool);
 	return;
     }
 
@@ -1165,6 +1189,7 @@
 	pjsua_perror(THIS_FILE, "Unable to create presence client", 
 		     status);
 	pjsip_dlg_terminate(buddy->dlg);
+	if (tmp_pool) pj_pool_release(tmp_pool);
 	return;
     }
 
@@ -1202,6 +1227,7 @@
 	buddy->sub = NULL;
 	pjsua_perror(THIS_FILE, "Unable to create initial SUBSCRIBE", 
 		     status);
+	if (tmp_pool) pj_pool_release(tmp_pool);
 	return;
     }
 
@@ -1215,8 +1241,11 @@
 	buddy->sub = NULL;
 	pjsua_perror(THIS_FILE, "Unable to send initial SUBSCRIBE", 
 		     status);
+	if (tmp_pool) pj_pool_release(tmp_pool);
 	return;
     }
+
+    if (tmp_pool) pj_pool_release(tmp_pool);
 }