Index: /pjproject/trunk/pjlib/src/pj/ioqueue_common_abs.c
===================================================================
--- /pjproject/trunk/pjlib/src/pj/ioqueue_common_abs.c	(revision 5736)
+++ /pjproject/trunk/pjlib/src/pj/ioqueue_common_abs.c	(revision 5737)
@@ -344,5 +344,5 @@
 				 "Send error for socket %d, retrying",
 				 h->fd));
-		    replace_udp_sock(h);
+		    send_rc = replace_udp_sock(h);
 		    continue;
 		}
@@ -579,5 +579,8 @@
 		h->fd_type==pj_SOCK_DGRAM())
 	    {
-		replace_udp_sock(h);
+		rc = replace_udp_sock(h);
+		if (rc != PJ_SUCCESS) {
+		    bytes_read = -rc;
+		}
 	    }
 #endif
Index: /pjproject/trunk/pjlib/src/pj/ioqueue_select.c
===================================================================
--- /pjproject/trunk/pjlib/src/pj/ioqueue_select.c	(revision 5736)
+++ /pjproject/trunk/pjlib/src/pj/ioqueue_select.c	(revision 5737)
@@ -728,64 +728,105 @@
     PJ_LOG(4,(THIS_FILE, "Attempting to replace UDP socket %d", old_sock));
 
-    /* Investigate the old socket */
-    addr_len = sizeof(local_addr);
-    status = pj_sock_getsockname(old_sock, &local_addr, &addr_len);
+    for (msec=20; (msec<1000 && status != PJ_SUCCESS) ;
+         msec<1000? msec=msec*2 : 1000)
+    {
+        if (msec > 20) {
+            PJ_LOG(4,(THIS_FILE, "Retry to replace UDP socket %d", old_sock));
+            pj_thread_sleep(msec);
+        }
+        
+        /* Investigate the old socket */
+        addr_len = sizeof(local_addr);
+        status = pj_sock_getsockname(old_sock, &local_addr, &addr_len);
+        if (status != PJ_SUCCESS) {
+            PJ_LOG(5,(THIS_FILE, "Error get socket name %d", status));
+            continue;
+        }
+        
+        addr_len = sizeof(rem_addr);
+        status = pj_sock_getpeername(old_sock, &rem_addr, &addr_len);
+        if (status != PJ_SUCCESS) {
+            PJ_LOG(5,(THIS_FILE, "Error get peer name %d", status));
+        } else {
+            flags |= HAS_PEER_ADDR;
+        }
+
+        status = pj_sock_get_qos_params(old_sock, &qos_params);
+        if (status == PJ_STATUS_FROM_OS(EBADF) ||
+            status == PJ_STATUS_FROM_OS(EINVAL))
+        {
+            PJ_LOG(5,(THIS_FILE, "Error get qos param %d", status));
+            continue;
+        }
+        
+        if (status != PJ_SUCCESS) {
+            PJ_LOG(5,(THIS_FILE, "Error get qos param %d", status));
+        } else {
+            flags |= HAS_QOS;
+        }
+
+        /* We're done with the old socket, close it otherwise we'll get
+         * error in bind()
+         */
+        status = pj_sock_close(old_sock);
+        if (status != PJ_SUCCESS) {
+            PJ_LOG(5,(THIS_FILE, "Error closing socket %d", status));
+        }
+
+        /* Prepare the new socket */
+        status = pj_sock_socket(local_addr.addr.sa_family, PJ_SOCK_DGRAM, 0,
+                                &new_sock);
+        if (status != PJ_SUCCESS) {
+            PJ_LOG(5,(THIS_FILE, "Error create socket %d", status));
+            continue;
+        }
+
+        /* Even after the socket is closed, we'll still get "Address in use"
+         * errors, so force it with SO_REUSEADDR
+         */
+        val = 1;
+        status = pj_sock_setsockopt(new_sock, SOL_SOCKET, SO_REUSEADDR,
+                                    &val, sizeof(val));
+        if (status == PJ_STATUS_FROM_OS(EBADF) ||
+            status == PJ_STATUS_FROM_OS(EINVAL))
+        {
+            PJ_LOG(5,(THIS_FILE, "Error set socket option %d",
+                      status));
+            continue;
+        }
+
+        /* The loop is silly, but what else can we do? */
+        addr_len = pj_sockaddr_get_len(&local_addr);
+        for (msec=20; msec<1000 ; msec<1000? msec=msec*2 : 1000) {
+            status = pj_sock_bind(new_sock, &local_addr, addr_len);
+            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)
+            continue;
+
+        if (flags & HAS_QOS) {
+            status = pj_sock_set_qos_params(new_sock, &qos_params);
+            if (status == PJ_STATUS_FROM_OS(EINVAL)) {
+                PJ_LOG(5,(THIS_FILE, "Error set qos param %d", status));
+                continue;
+            }
+        }
+
+        if (flags & HAS_PEER_ADDR) {
+            status = pj_sock_connect(new_sock, &rem_addr, addr_len);
+            if (status != PJ_SUCCESS) {
+                PJ_LOG(5,(THIS_FILE, "Error connect socket %d", status));
+                continue;
+            }
+        }
+    }
+    
     if (status != PJ_SUCCESS)
-	goto on_error;
+        goto on_error;
     
-    addr_len = sizeof(rem_addr);
-    status = pj_sock_getpeername(old_sock, &rem_addr, &addr_len);
-    if (status == PJ_SUCCESS)
-	flags |= HAS_PEER_ADDR;
-
-    status = pj_sock_get_qos_params(old_sock, &qos_params);
-    if (status == PJ_SUCCESS)
-	flags |= HAS_QOS;
-
-    /* We're done with the old socket, close it otherwise we'll get
-     * error in bind()
-     */
-    pj_sock_close(old_sock);
-
-    /* Prepare the new socket */
-    status = pj_sock_socket(local_addr.addr.sa_family, PJ_SOCK_DGRAM, 0,
-			    &new_sock);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-    /* Even after the socket is closed, we'll still get "Address in use"
-     * errors, so force it with SO_REUSEADDR
-     */
-    val = 1;
-    status = pj_sock_setsockopt(new_sock, SOL_SOCKET, SO_REUSEADDR,
-				&val, sizeof(val));
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-    /* The loop is silly, but what else can we do? */
-    addr_len = pj_sockaddr_get_len(&local_addr);
-    for (msec=20; ; msec<1000? msec=msec*2 : 1000) {
-	status = pj_sock_bind(new_sock, &local_addr, addr_len);
-	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)
-	goto on_error;
-
-    if (flags & HAS_QOS) {
-	status = pj_sock_set_qos_params(new_sock, &qos_params);
-	if (status != PJ_SUCCESS)
-	    goto on_error;
-    }
-
-    if (flags & HAS_PEER_ADDR) {
-	status = pj_sock_connect(new_sock, &rem_addr, addr_len);
-	if (status != PJ_SUCCESS)
-	    goto on_error;
-    }
-
     /* Set socket to nonblocking. */
     val = 1;
@@ -830,7 +871,7 @@
     if (new_sock != PJ_INVALID_SOCKET)
 	pj_sock_close(new_sock);
-    PJ_PERROR(1,(THIS_FILE, status, "Error replacing socket"));
+    PJ_PERROR(1,(THIS_FILE, status, "Error replacing socket [%d]", status));
     pj_lock_release(h->ioqueue->lock);
-    return status;
+    return PJ_ESOCKETSTOP;
 }
 #endif
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 5736)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 5737)
@@ -70,4 +70,5 @@
     unsigned		tx_drop_pct;	/**< Percent of tx pkts to drop.    */
     unsigned		rx_drop_pct;	/**< Percent of rx pkts to drop.    */
+    pj_ioqueue_t	*ioqueue;	/**< Ioqueue instance.		    */
 
     pj_sock_t	        rtp_sock;	/**< RTP socket			    */
@@ -152,4 +153,7 @@
 static pj_status_t transport_destroy  (pjmedia_transport *tp);
 
+static pj_status_t transport_restart  (pj_bool_t is_rtp, 
+				       struct transport_udp *udp);
+
 
 static pjmedia_transport_op transport_udp_op = 
@@ -387,4 +391,5 @@
 	goto on_error;
 
+    tp->ioqueue = ioqueue;
 
     /* Done */
@@ -441,7 +446,7 @@
 
 /* Notification from ioqueue about incoming RTP packet */
-static void on_rx_rtp( pj_ioqueue_key_t *key, 
-                       pj_ioqueue_op_key_t *op_key, 
-                       pj_ssize_t bytes_read)
+static void on_rx_rtp(pj_ioqueue_key_t *key,
+		      pj_ioqueue_op_key_t *op_key,
+		      pj_ssize_t bytes_read)
 {
     struct transport_udp *udp;
@@ -451,4 +456,20 @@
 
     udp = (struct transport_udp*) pj_ioqueue_get_user_data(key);
+
+#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
+	    PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
+    if (-bytes_read == PJ_ESOCKETSTOP) {
+	/* Try to recover by restarting the transport. */
+	PJ_LOG(4, (udp->base.name, "Restarting RTP transport"));
+	status = transport_restart(PJ_TRUE, udp);
+	if (status == PJ_SUCCESS) {
+	    PJ_LOG(4, (udp->base.name, "Success restarting RTP transport"));
+	} else {
+	    PJ_PERROR(1, (udp->base.name, status, 
+			  "Error restarting RTP transport"));
+	}
+	return;
+    }
+#endif
 
     do {
@@ -565,4 +586,20 @@
 
     udp = (struct transport_udp*) pj_ioqueue_get_user_data(key);
+
+#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
+	    PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
+    if (-bytes_read == PJ_ESOCKETSTOP) {
+	/* Try to recover by restarting the transport. */
+	PJ_LOG(4, (udp->base.name, "Restarting RTCP transport"));
+	status = transport_restart(PJ_FALSE, udp);
+	if (status == PJ_SUCCESS) {
+	    PJ_LOG(4, (udp->base.name, "Success restarting RTCP transport"));
+	} else {
+	    PJ_PERROR(1, (udp->base.name, status, 
+			  "Error restarting RTCP transport"));
+	}
+	return;
+    }
+#endif
 
     do {
@@ -996,2 +1033,124 @@
 }
 
+static pj_status_t transport_restart(pj_bool_t is_rtp,
+				     struct transport_udp *udp)
+{
+    pj_ioqueue_key_t *key = (is_rtp ? udp->rtp_key : udp->rtcp_key);
+    pj_sock_t *sock = (is_rtp ? &udp->rtp_sock : &udp->rtcp_sock);
+    pj_status_t status;
+    int af;
+    pj_sockaddr *addr;
+    pj_ioqueue_callback cb;
+    pj_ssize_t size;
+
+    /* Destroy existing socket, if any. */    
+    if (key) {
+	/* This will block the execution if callback is still
+	 * being called.
+	 */
+	pj_ioqueue_unregister(key);
+	if (is_rtp) {
+	    udp->rtp_key = NULL;
+	} else {
+	    udp->rtcp_key = NULL;
+	}
+    } else if (*sock != PJ_INVALID_SOCKET) {
+	pj_sock_close(*sock);
+    }
+    *sock = PJ_INVALID_SOCKET;
+
+    /* Create socket */
+    af = udp->rtp_addr_name.addr.sa_family;
+    status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, sock);
+
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    addr = (is_rtp) ? &udp->rtp_addr_name : &udp->rtcp_addr_name;
+    status = pj_sock_bind(*sock, addr, pj_sockaddr_get_len(addr));
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    /* Set buffer size for RTP socket */
+#if PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE
+    {
+	unsigned sobuf_size = PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE;
+
+	status = pj_sock_setsockopt_sobuf(udp->rtp_sock, pj_SO_RCVBUF(),
+					  PJ_TRUE, &sobuf_size);
+	if (status != PJ_SUCCESS) {
+	    pj_perror(3, udp->base.name, status, "Failed setting SO_RCVBUF");
+	} else {
+	    if (sobuf_size < PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE) {
+		PJ_LOG(4, (udp->base.name,
+			   "Warning! Cannot set SO_RCVBUF as configured, "
+			   "now=%d, configured=%d",
+			   sobuf_size, PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE));
+	    } else {
+		PJ_LOG(5, (udp->base.name, "SO_RCVBUF set to %d", sobuf_size));
+	    }
+	}
+    }
+#endif
+#if PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE
+    {
+	unsigned sobuf_size = PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE;
+
+	status = pj_sock_setsockopt_sobuf(udp->rtp_sock, pj_SO_SNDBUF(),
+					  PJ_TRUE, &sobuf_size);
+	if (status != PJ_SUCCESS) {
+	    pj_perror(3, udp->base.name, status, "Failed setting SO_SNDBUF");
+	} else {
+	    if (sobuf_size < PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE) {
+		PJ_LOG(4, (udp->base.name,
+			   "Warning! Cannot set SO_SNDBUF as configured, "
+			   "now=%d, configured=%d",
+			   sobuf_size, PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE));
+	    } else {
+		PJ_LOG(5, (udp->base.name, "SO_SNDBUF set to %d", sobuf_size));
+	    }
+	}
+    }
+#endif
+    pj_bzero(&cb, sizeof(cb));
+    if (is_rtp)
+	cb.on_read_complete = &on_rx_rtp;
+    else 
+	cb.on_read_complete = &on_rx_rtcp;
+
+    if (is_rtp) {
+	status = pj_ioqueue_register_sock(udp->pool, udp->ioqueue, *sock, udp,
+					  &cb, &udp->rtp_key);
+    } else {
+	status = pj_ioqueue_register_sock(udp->pool, udp->ioqueue, *sock, udp,
+					  &cb, &udp->rtcp_key);    
+    }
+
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    if (is_rtp) {
+	size = sizeof(udp->rtp_pkt);
+	status = pj_ioqueue_recvfrom(udp->rtp_key, &udp->rtp_read_op,
+				     udp->rtp_pkt, &size, 
+				     PJ_IOQUEUE_ALWAYS_ASYNC,
+				     &udp->rtp_src_addr, &udp->rtp_addrlen);
+    } else {
+	size = sizeof(udp->rtcp_pkt);
+	status = pj_ioqueue_recvfrom(udp->rtcp_key, &udp->rtcp_read_op,
+				     udp->rtcp_pkt, &size, 
+				     PJ_IOQUEUE_ALWAYS_ASYNC,
+				     &udp->rtcp_src_addr, &udp->rtcp_addr_len);
+    }
+    if (status != PJ_EPENDING)
+	goto on_error;
+
+
+    return PJ_SUCCESS;
+on_error:
+    if (*sock != PJ_INVALID_SOCKET) {
+	pj_sock_close(*sock);
+	*sock = PJ_INVALID_SOCKET;
+    }
+    return status;
+}
Index: /pjproject/trunk/pjsip/src/pjsip/sip_transport_udp.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_transport_udp.c	(revision 5736)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_transport_udp.c	(revision 5737)
@@ -143,4 +143,25 @@
 	goto on_return;
 
+#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
+    	    PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
+    if (-bytes_read == PJ_ESOCKETSTOP) {
+	--tp->read_loop_spin;
+	/* Try to recover by restarting the transport. */
+	PJ_LOG(4,(tp->base.obj_name, "Restarting SIP UDP transport"));
+	status = pjsip_udp_transport_restart2(
+			    &tp->base,
+			    PJSIP_UDP_TRANSPORT_DESTROY_SOCKET,
+			    PJ_INVALID_SOCKET,
+			    &tp->base.local_addr,
+			    &tp->base.local_name);
+
+	if (status != PJ_SUCCESS) {
+	    PJ_PERROR(1,(THIS_FILE, status,
+			 "Error restarting SIP UDP transport"));
+	}
+        return;
+    }
+#endif
+
     /*
      * The idea of the loop is to process immediate data received by
@@ -262,5 +283,4 @@
 		    status != PJ_STATUS_FROM_OS(OSERR_ECONNRESET)) 
 		{
-
 		    PJSIP_ENDPT_LOG_ERROR((rdata->tp_info.transport->endpt,
 					   rdata->tp_info.transport->obj_name,
@@ -305,4 +325,25 @@
     tdata_op_key->tdata = NULL;
 
+#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
+    	    PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
+    if (-bytes_sent == PJ_ESOCKETSTOP) {
+	pj_status_t status;
+	/* Try to recover by restarting the transport. */
+	PJ_LOG(4,(tp->base.obj_name, "Restarting SIP UDP transport"));
+	status = pjsip_udp_transport_restart2(
+			    &tp->base,
+			    PJSIP_UDP_TRANSPORT_DESTROY_SOCKET,
+			    PJ_INVALID_SOCKET,
+			    &tp->base.local_addr,
+			    &tp->base.local_name);
+
+	if (status != PJ_SUCCESS) {
+	    PJ_PERROR(1,(THIS_FILE, status,
+			 "Error restarting SIP UDP transport"));
+	}
+        return;
+    }
+#endif
+
     if (tdata_op_key->callback) {
 	tdata_op_key->callback(&tp->base, tdata_op_key->token, bytes_sent);
@@ -562,4 +603,11 @@
 
     pj_assert(a_name->host.slen != 0);
+    
+    if (pj_strcmp(&tp->base.local_name.host, &a_name->host) == 0 &&
+        tp->base.local_name.port == a_name->port)
+    {
+        return;
+    }
+    
     pj_strdup_with_null(tp->base.pool, &tp->base.local_name.host, 
 			&a_name->host);
@@ -1133,6 +1181,7 @@
 	/* Create the socket if it's not specified */
 	if (sock == PJ_INVALID_SOCKET) {
-	    status = create_socket(local->addr.sa_family, local, 
-				   pj_sockaddr_get_len(local), &sock);
+	    status = create_socket(local?local->addr.sa_family:pj_AF_UNSPEC(), 
+				   local, local?pj_sockaddr_get_len(local):0, 
+				   &sock);
 	    if (status != PJ_SUCCESS)
 		return status;
