Ticket #364: Upon unregistration, (un)REGISTER should be sent only after (un)PUBLISH has completed successfully
 - wait for unpublication to complete or some delay expires, before sending unregistration
 - added unpublish_max_wait_time_msec field in account config to control how long to wait


git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@2942 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index cc26bc8..39ad80d 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -162,6 +162,7 @@
 
     cfg->reg_timeout = PJSUA_REG_INTERVAL;
     pjsip_publishc_opt_default(&cfg->publish_opt);
+    cfg->unpublish_max_wait_time_msec = PJSUA_UNPUBLISH_MAX_WAIT_TIME_MSEC;
     cfg->transport_id = PJSUA_INVALID_ID;
     cfg->allow_contact_rewrite = PJ_TRUE;
     cfg->require_100rel = pjsua_var.ua_cfg.require_100rel;
@@ -1228,6 +1229,8 @@
     }
     
     if (pjsua_var.endpt) {
+	unsigned max_wait;
+
 	/* Terminate all calls. */
 	pjsua_call_hangup_all();
 
@@ -1242,6 +1245,42 @@
 	/* Terminate all presence subscriptions. */
 	pjsua_pres_shutdown();
 
+	/* Wait for sometime until all publish client sessions are done
+	 * (ticket #364)
+	 */
+	/* First stage, get the maximum wait time */
+	max_wait = 100;
+	for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
+	    if (!pjsua_var.acc[i].valid)
+		continue;
+	    if (pjsua_var.acc[i].cfg.unpublish_max_wait_time_msec > max_wait)
+		max_wait = pjsua_var.acc[i].cfg.unpublish_max_wait_time_msec;
+	}
+	
+	/* Second stage, wait for unpublications to complete */
+	for (i=0; i<(int)(max_wait/50); ++i) {
+	    unsigned j;
+	    for (j=0; j<PJ_ARRAY_SIZE(pjsua_var.acc); ++j) {
+		if (!pjsua_var.acc[j].valid)
+		    continue;
+
+		if (pjsua_var.acc[j].publish_sess)
+		    break;
+	    }
+	    if (j != PJ_ARRAY_SIZE(pjsua_var.acc))
+		busy_sleep(50);
+	    else
+		break;
+	}
+
+	/* Third stage, forcefully destroy unfinished unpublications */
+	for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
+	    if (pjsua_var.acc[i].publish_sess) {
+		pjsip_publishc_destroy(pjsua_var.acc[i].publish_sess);
+		pjsua_var.acc[i].publish_sess = NULL;
+	    }
+	}
+
 	/* Unregister all accounts */
 	for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
 	    if (!pjsua_var.acc[i].valid)