Index: pjproject/trunk/pjlib-util/src/pjlib-util/cli_telnet.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjlib-util/cli_telnet.c	(revision 4440)
+++ pjproject/trunk/pjlib-util/src/pjlib-util/cli_telnet.c	(revision 4461)
@@ -30,4 +30,13 @@
 #include <pjlib-util/errno.h>
 #include <pjlib-util/scanner.h>
+#include <pj/addr_resolv.h>
+#include <pj/compat/socket.h>
+
+#if (defined(PJ_WIN32) && PJ_WIN32!=0) || \
+    (defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0)
+
+#define EADDRINUSE WSAEADDRINUSE 
+
+#endif
 
 #define CLI_TELNET_BUF_SIZE 256
@@ -45,4 +54,12 @@
 
 #define MAX_CLI_TELNET_OPTIONS 256
+/** Maximum retry on Telnet Restart **/
+#define MAX_RETRY_ON_TELNET_RESTART 100
+/** Minimum number of millisecond to wait before retrying to re-bind on
+ * telnet restart **/
+#define MIN_WAIT_ON_TELNET_RESTART 20
+/** Maximum number of millisecod to wait before retrying to re-bind on
+ *  telnet restart **/
+#define MAX_WAIT_ON_TELNET_RESTART 1000
 
 /**
@@ -262,5 +279,5 @@
 } cli_telnet_sess;
 
-struct cli_telnet_fe
+typedef struct cli_telnet_fe
 {
     pj_cli_front_end        base;
@@ -273,6 +290,6 @@
     pj_thread_t            *worker_thread;
     pj_bool_t               is_quitting;
-    pj_mutex_t             *mutex;
-};
+    pj_mutex_t             *mutex;    
+} cli_telnet_fe;
 
 /* Forward Declaration */
@@ -282,4 +299,7 @@
 static pj_status_t telnet_sess_send(cli_telnet_sess *sess,
                                     const pj_str_t *str);
+
+static pj_status_t telnet_start(cli_telnet_fe *fe);
+static pj_status_t telnet_restart(cli_telnet_fe *tfe);
 
 /**
@@ -646,5 +666,5 @@
     pj_str_t send_data;
     char data_str[128];
-    struct cli_telnet_fe *fe = (struct cli_telnet_fe *)sess->base.fe;
+    cli_telnet_fe *fe = (cli_telnet_fe *)sess->base.fe;
 
     send_data.ptr = &data_str[0];
@@ -670,5 +690,5 @@
     unsigned len;
     unsigned i;
-    struct cli_telnet_fe *fe = (struct cli_telnet_fe *)sess->base.fe;
+    cli_telnet_fe *fe = (cli_telnet_fe *)sess->base.fe;
 
     send_data.ptr = &data_str[0];
@@ -744,5 +764,5 @@
     pj_str_t send_data;
     char data[1028];
-    struct cli_telnet_fe *fe = (struct cli_telnet_fe *)sess->base.fe;
+    cli_telnet_fe *fe = (cli_telnet_fe *)sess->base.fe;
     const pj_cli_hint_info *hint = info->hint;
     out_parse_state parse_state = OP_NORMAL;
@@ -1319,5 +1339,5 @@
 {
     cli_telnet_sess *tsess = (cli_telnet_sess *)sess;
-    pj_mutex_t *mutex = ((struct cli_telnet_fe *)sess->fe)->mutex;
+    pj_mutex_t *mutex = ((cli_telnet_fe *)sess->fe)->mutex;
 
     pj_mutex_lock(mutex);
@@ -1335,5 +1355,5 @@
 		                const char *data, int len)
 {
-    struct cli_telnet_fe * tfe = (struct cli_telnet_fe *)fe;
+    cli_telnet_fe *tfe = (cli_telnet_fe *)fe;
     pj_cli_sess *sess;    
 
@@ -1358,5 +1378,5 @@
 static void telnet_fe_destroy(pj_cli_front_end *fe)
 {
-    struct cli_telnet_fe *tfe = (struct cli_telnet_fe *)fe;
+    cli_telnet_fe *tfe = (cli_telnet_fe *)fe;
     pj_cli_sess *sess;
 
@@ -1392,5 +1412,5 @@
 static int poll_worker_thread(void *p)
 {
-    struct cli_telnet_fe *fe = (struct cli_telnet_fe *)p;
+    cli_telnet_fe *fe = (cli_telnet_fe *)p;
 
     while (!fe->is_quitting) {
@@ -1409,7 +1429,8 @@
 			    pj_activesock_get_user_data(asock);
 
-    PJ_UNUSED_ARG(op_key);
+    PJ_UNUSED_ARG(op_key);    
 
     if (sent <= 0) {
+	TRACE_((THIS_FILE, "Error On data send"));
         pj_cli_sess_end_session(&sess->base);
         return PJ_FALSE;
@@ -1442,5 +1463,5 @@
     cli_telnet_sess *sess = (cli_telnet_sess *)
                             pj_activesock_get_user_data(asock);
-    struct cli_telnet_fe *tfe = (struct cli_telnet_fe *)sess->base.fe;
+    cli_telnet_fe *tfe = (cli_telnet_fe *)sess->base.fe;
     unsigned char *cdata = (unsigned char*)data;    
     pj_status_t is_valid = PJ_TRUE;
@@ -1449,11 +1470,11 @@
     PJ_UNUSED_ARG(remainder);
 
-    if (status != PJ_SUCCESS && status != PJ_EPENDING) {
-        pj_cli_sess_end_session(&sess->base);
-        return PJ_FALSE;
-    }
-
     if (tfe->is_quitting)
         return PJ_FALSE;
+
+    if (status != PJ_SUCCESS && status != PJ_EPENDING) {
+	TRACE_((THIS_FILE, "Error on data read %d", status));
+        return PJ_FALSE;
+    }    
 
     pj_mutex_lock(sess->smutex);
@@ -1552,11 +1573,12 @@
 				     pj_sock_t newsock,
 				     const pj_sockaddr_t *src_addr,
-				     int src_addr_len)
-{
-    struct cli_telnet_fe *fe = (struct cli_telnet_fe *)
-                                pj_activesock_get_user_data(asock);
+				     int src_addr_len,
+				     pj_status_t status)
+{
+    cli_telnet_fe *fe = (cli_telnet_fe *) pj_activesock_get_user_data(asock);
+
     pj_status_t sstatus;
     pj_pool_t *pool;
-    cli_telnet_sess *sess;
+    cli_telnet_sess *sess = NULL;
     pj_activesock_cb asock_cb;
 
@@ -1566,4 +1588,12 @@
     if (fe->is_quitting)
         return PJ_FALSE;
+
+    if (status != PJ_SUCCESS && status != PJ_EPENDING) {
+	TRACE_((THIS_FILE, "Error on data accept %d", status));
+	if (status == PJ_ESOCKETSTOP) 
+	    telnet_restart(fe);	    
+	
+        return PJ_FALSE;
+    }    
 
     /* An incoming connection is accepted, create a new session */
@@ -1658,10 +1688,7 @@
 					 pj_cli_front_end **p_fe)
 {
-    struct cli_telnet_fe *fe;
+    cli_telnet_fe *fe;
     pj_pool_t *pool;
-    pj_sock_t sock = PJ_INVALID_SOCKET;
-    pj_activesock_cb asock_cb;
-    pj_sockaddr_in addr;
-    pj_status_t sstatus;
+    pj_status_t status;   
 
     PJ_ASSERT_RETURN(cli, PJ_EINVAL);
@@ -1670,5 +1697,5 @@
                           PJ_CLI_TELNET_POOL_SIZE, PJ_CLI_TELNET_POOL_INC,
                           NULL);
-    fe = PJ_POOL_ZALLOC_T(pool, struct cli_telnet_fe);
+    fe = PJ_POOL_ZALLOC_T(pool, cli_telnet_fe);
     if (!fe)
         return PJ_ENOMEM;
@@ -1688,40 +1715,84 @@
     fe->pool = pool;
 
-    if (!fe->cfg.ioqueue) {
+    if (!fe->cfg.ioqueue) {	
         /* Create own ioqueue if application doesn't supply one */
-        sstatus = pj_ioqueue_create(pool, 8, &fe->cfg.ioqueue);
-        if (sstatus != PJ_SUCCESS)
+        status = pj_ioqueue_create(pool, 8, &fe->cfg.ioqueue);
+        if (status != PJ_SUCCESS)
             goto on_exit;
         fe->own_ioqueue = PJ_TRUE;
     }
 
-    sstatus = pj_mutex_create_recursive(pool, "mutex_telnet_fe", &fe->mutex);
-    if (sstatus != PJ_SUCCESS)
+    status = pj_mutex_create_recursive(pool, "mutex_telnet_fe", &fe->mutex);
+    if (status != PJ_SUCCESS)
         goto on_exit;
 
     /* Start telnet daemon */
-    sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, 
-                             &sock);
-    if (sstatus != PJ_SUCCESS)
+    telnet_start(fe);
+
+    pj_cli_register_front_end(cli, &fe->base);
+
+    if (p_fe)
+        *p_fe = &fe->base;
+
+    return PJ_SUCCESS;
+
+on_exit:
+    if (fe->own_ioqueue)
+        pj_ioqueue_destroy(fe->cfg.ioqueue);
+
+    if (fe->mutex)
+        pj_mutex_destroy(fe->mutex);
+
+    pj_pool_release(pool);
+    return status;
+}
+
+static pj_status_t telnet_start(cli_telnet_fe *fe)
+{
+    pj_sock_t sock = PJ_INVALID_SOCKET;
+    pj_activesock_cb asock_cb;
+    pj_sockaddr_in addr;
+    pj_status_t status;   
+    int val;
+    int restart_retry;
+    unsigned msec;
+
+    /* Start telnet daemon */
+    status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock);
+
+    if (status != PJ_SUCCESS)
         goto on_exit;
 
     pj_sockaddr_in_init(&addr, NULL, fe->cfg.port);
 
-    sstatus = pj_sock_bind(sock, &addr, sizeof(addr));
-    if (sstatus == PJ_SUCCESS) {
-	pj_sockaddr_in addr;
-	int addr_len = sizeof(addr);
-
-	sstatus = pj_sock_getsockname(sock, &addr, &addr_len);
-	if (sstatus != PJ_SUCCESS)
+    val = 1;
+    status = pj_sock_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+				&val, sizeof(val));
+
+    if (status != PJ_SUCCESS)
+	goto on_exit;
+
+    /* The loop is silly, but what else can we do? */
+    for (msec=MIN_WAIT_ON_TELNET_RESTART, restart_retry=0;
+	 restart_retry < MAX_RETRY_ON_TELNET_RESTART;
+	 ++restart_retry, msec=(msec<MAX_WAIT_ON_TELNET_RESTART?
+		          msec*2 : MAX_WAIT_ON_TELNET_RESTART))
+    {
+	status = pj_sock_bind(sock, &addr, sizeof(addr));
+	if (status != PJ_STATUS_FROM_OS(EADDRINUSE))
+	    break;
+	PJ_LOG(4,(THIS_FILE, "Address is still in use, retrying.."));
+	pj_thread_sleep(msec);
+    }    
+    
+    if (status == PJ_SUCCESS) {	
+	int addr_len = sizeof(addr);	
+
+	status = pj_sock_getsockname(sock, &addr, &addr_len);
+	if (status != PJ_SUCCESS)
 	    goto on_exit;
 	    
-        fe->cfg.port = pj_sockaddr_in_get_port(&addr);
-	if (param) 
-	    param->port = fe->cfg.port;
-	
-        PJ_LOG(3, (THIS_FILE, "CLI telnet daemon listening at port %d",
-		   fe->cfg.port));
-	
+        fe->cfg.port = pj_sockaddr_in_get_port(&addr);	
+
 	if (fe->cfg.prompt_str.slen == 0) {
 	    pj_str_t prompt_sign = {"> ", 2};
@@ -1738,33 +1809,49 @@
     }
 
-    sstatus = pj_sock_listen(sock, 4);
-    if (sstatus != PJ_SUCCESS)
+    status = pj_sock_listen(sock, 4);
+    if (status != PJ_SUCCESS)
         goto on_exit;
 
     pj_bzero(&asock_cb, sizeof(asock_cb));
-    asock_cb.on_accept_complete = &telnet_fe_on_accept;
-    sstatus = pj_activesock_create(pool, sock, pj_SOCK_STREAM(),
-                                   NULL, fe->cfg.ioqueue,
-		                   &asock_cb, fe, &fe->asock);
-    if (sstatus != PJ_SUCCESS)
+    asock_cb.on_accept_complete2 = &telnet_fe_on_accept;
+    status = pj_activesock_create(fe->pool, sock, pj_SOCK_STREAM(),
+                                  NULL, fe->cfg.ioqueue,
+		                  &asock_cb, fe, &fe->asock);
+    if (status != PJ_SUCCESS)
         goto on_exit;
 
-    sstatus = pj_activesock_start_accept(fe->asock, pool);
-    if (sstatus != PJ_SUCCESS)
+    status = pj_activesock_start_accept(fe->asock, fe->pool);
+    if (status != PJ_SUCCESS)
         goto on_exit;
 
     if (fe->own_ioqueue) {
         /* Create our own worker thread */
-        sstatus = pj_thread_create(pool, "worker_telnet_fe",
-                                   &poll_worker_thread, fe, 0, 0,
-                                   &fe->worker_thread);
-        if (sstatus != PJ_SUCCESS)
+        status = pj_thread_create(fe->pool, "worker_telnet_fe",
+                                  &poll_worker_thread, fe, 0, 0,
+                                  &fe->worker_thread);
+        if (status != PJ_SUCCESS)
             goto on_exit;
     }
 
-    pj_cli_register_front_end(cli, &fe->base);
-
-    if (p_fe)
-        *p_fe = &fe->base;
+    /** Fill telnet information and call pj_cli_telnet_on_started callback */
+    if (fe->cfg.on_started) {
+	char ip_addr[32];
+	pj_cli_telnet_info telnet_info;
+	pj_sockaddr hostip;
+
+	telnet_info.ip_address.ptr = ip_addr;
+	telnet_info.ip_address.slen = 0;
+	
+	status = pj_gethostip(pj_AF_INET(), &hostip);
+	if (status != PJ_SUCCESS)
+	    goto on_exit;
+
+	pj_strcpy2(&telnet_info.ip_address, 
+		   pj_inet_ntoa(hostip.ipv4.sin_addr));
+
+	telnet_info.port = fe->cfg.port;
+
+	(*fe->cfg.on_started)(&telnet_info);
+    }
 
     return PJ_SUCCESS;
@@ -1782,5 +1869,47 @@
         pj_mutex_destroy(fe->mutex);
 
-    pj_pool_release(pool);
-    return sstatus;
-}
+    pj_pool_release(fe->pool);
+    return status;
+}
+
+static pj_status_t telnet_restart(cli_telnet_fe *fe)
+{
+    pj_status_t status;
+    pj_cli_sess *sess;      
+
+    fe->is_quitting = PJ_TRUE;
+    if (fe->worker_thread) {	
+	pj_thread_join(fe->worker_thread);
+    }
+
+    pj_mutex_lock(fe->mutex);
+
+    /* Destroy all the sessions */
+    sess = fe->sess_head.next;
+    while (sess != &fe->sess_head) {
+	(*sess->op->destroy)(sess);
+	sess = fe->sess_head.next;
+    }
+
+    pj_mutex_unlock(fe->mutex);
+
+    /** Close existing activesock **/
+    status = pj_activesock_close(fe->asock);
+    if (status != PJ_SUCCESS)
+	goto on_exit;
+
+    if (fe->worker_thread) {
+	pj_thread_destroy(fe->worker_thread);
+	fe->worker_thread = NULL;
+    }
+
+    fe->is_quitting = PJ_FALSE;
+
+    /** Start Telnet **/
+    status = telnet_start(fe);
+    if (status == PJ_SUCCESS)
+	TRACE_((THIS_FILE, "Telnet Restarted"));
+    
+on_exit:
+    return status;
+}
