Index: /pjproject/trunk/pjlib-util/build/pjlib_util.vcproj
===================================================================
--- /pjproject/trunk/pjlib-util/build/pjlib_util.vcproj	(revision 1103)
+++ /pjproject/trunk/pjlib-util/build/pjlib_util.vcproj	(revision 1104)
@@ -17,6 +17,6 @@
 		<Configuration
 			Name="Release|Win32"
-			OutputDirectory=".\./output/pjlib-util-i386-win32-vc6-release"
-			IntermediateDirectory=".\./output/pjlib-util-i386-win32-vc6-release"
+			OutputDirectory="./output/pjlib-util-i386-win32-vc8-release"
+			IntermediateDirectory="./output/pjlib-util-i386-win32-vc8-release"
 			ConfigurationType="4"
 			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
@@ -49,8 +49,8 @@
 				RuntimeLibrary="2"
 				EnableFunctionLevelLinking="true"
-				PrecompiledHeaderFile=".\./output/pjlib-util-i386-win32-vc6-release/pjlib_util.pch"
-				AssemblerListingLocation=".\./output/pjlib-util-i386-win32-vc6-release/"
-				ObjectFile=".\./output/pjlib-util-i386-win32-vc6-release/"
-				ProgramDataBaseFileName=".\./output/pjlib-util-i386-win32-vc6-release/"
+				PrecompiledHeaderFile="./output/pjlib-util-i386-win32-vc8-release/pjlib_util.pch"
+				AssemblerListingLocation="./output/pjlib-util-i386-win32-vc8-release/"
+				ObjectFile="./output/pjlib-util-i386-win32-vc8-release/"
+				ProgramDataBaseFileName="./output/pjlib-util-i386-win32-vc8-release/"
 				BrowseInformation="1"
 				WarningLevel="4"
@@ -71,5 +71,5 @@
 			<Tool
 				Name="VCLibrarianTool"
-				OutputFile="../lib/pjlib-util-i386-win32-vc6-release.lib"
+				OutputFile="../lib/pjlib-util-i386-win32-vc8-release.lib"
 				SuppressStartupBanner="true"
 			/>
@@ -83,5 +83,5 @@
 				Name="VCBscMakeTool"
 				SuppressStartupBanner="true"
-				OutputFile=".\./output/pjlib-util-i386-win32-vc6-release/pjlib_util.bsc"
+				OutputFile="./output/pjlib-util-i386-win32-vc8-release/pjlib_util.bsc"
 			/>
 			<Tool
@@ -94,6 +94,6 @@
 		<Configuration
 			Name="Debug|Win32"
-			OutputDirectory=".\./output/pjlib-util-i386-win32-vc6-debug"
-			IntermediateDirectory=".\./output/pjlib-util-i386-win32-vc6-debug"
+			OutputDirectory="./output/pjlib-util-i386-win32-vc8-debug"
+			IntermediateDirectory="./output/pjlib-util-i386-win32-vc8-debug"
 			ConfigurationType="4"
 			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
@@ -125,8 +125,8 @@
 				BasicRuntimeChecks="3"
 				RuntimeLibrary="1"
-				PrecompiledHeaderFile=".\./output/pjlib-util-i386-win32-vc6-debug/pjlib_util.pch"
-				AssemblerListingLocation=".\./output/pjlib-util-i386-win32-vc6-debug/"
-				ObjectFile=".\./output/pjlib-util-i386-win32-vc6-debug/"
-				ProgramDataBaseFileName=".\./output/pjlib-util-i386-win32-vc6-debug/"
+				PrecompiledHeaderFile="./output/pjlib-util-i386-win32-vc8-debug/pjlib_util.pch"
+				AssemblerListingLocation="./output/pjlib-util-i386-win32-vc8-debug/"
+				ObjectFile="./output/pjlib-util-i386-win32-vc8-debug/"
+				ProgramDataBaseFileName="./output/pjlib-util-i386-win32-vc8-debug/"
 				BrowseInformation="1"
 				WarningLevel="4"
@@ -147,5 +147,5 @@
 			<Tool
 				Name="VCLibrarianTool"
-				OutputFile="../lib/pjlib-util-i386-win32-vc6-debug.lib"
+				OutputFile="../lib/pjlib-util-i386-win32-vc8-debug.lib"
 				SuppressStartupBanner="true"
 			/>
@@ -159,5 +159,5 @@
 				Name="VCBscMakeTool"
 				SuppressStartupBanner="true"
-				OutputFile=".\./output/pjlib-util-i386-win32-vc6-debug/pjlib_util.bsc"
+				OutputFile="./output/pjlib-util-i386-win32-vc8-debug/pjlib_util.bsc"
 			/>
 			<Tool
Index: /pjproject/trunk/pjlib/build/pjlib.dsp
===================================================================
--- /pjproject/trunk/pjlib/build/pjlib.dsp	(revision 1103)
+++ /pjproject/trunk/pjlib/build/pjlib.dsp	(revision 1104)
@@ -111,4 +111,9 @@
 # Begin Source File
 
+SOURCE=..\src\pj\ip_helper_generic.c
+# PROP Exclude_From_Build 1
+# End Source File
+# Begin Source File
+
 SOURCE=..\src\pj\log_writer_printk.c
 # PROP Exclude_From_Build 1
@@ -252,4 +257,8 @@
 !ENDIF 
 
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\pj\ip_helper_win32.c
 # End Source File
 # Begin Source File
@@ -516,4 +525,8 @@
 
 SOURCE=..\include\pj\ioqueue.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\pj\ip_helper.h
 # End Source File
 # Begin Source File
Index: /pjproject/trunk/pjlib/build/pjlib.vcproj
===================================================================
--- /pjproject/trunk/pjlib/build/pjlib.vcproj	(revision 1103)
+++ /pjproject/trunk/pjlib/build/pjlib.vcproj	(revision 1104)
@@ -17,6 +17,6 @@
 		<Configuration
 			Name="Debug|Win32"
-			OutputDirectory=".\output\pjlib-i386-win32-vc6-debug"
-			IntermediateDirectory=".\output\pjlib-i386-win32-vc6-debug"
+			OutputDirectory=".\output\pjlib-i386-win32-vc8-debug"
+			IntermediateDirectory=".\output\pjlib-i386-win32-vc8-debug"
 			ConfigurationType="4"
 			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
@@ -48,8 +48,8 @@
 				BasicRuntimeChecks="3"
 				RuntimeLibrary="1"
-				PrecompiledHeaderFile=".\output\pjlib-i386-win32-vc6-debug/pjlib.pch"
-				AssemblerListingLocation=".\output\pjlib-i386-win32-vc6-debug/"
-				ObjectFile=".\output\pjlib-i386-win32-vc6-debug/"
-				ProgramDataBaseFileName=".\output\pjlib-i386-win32-vc6-debug/"
+				PrecompiledHeaderFile=".\output\pjlib-i386-win32-vc8-debug/pjlib.pch"
+				AssemblerListingLocation=".\output\pjlib-i386-win32-vc8-debug/"
+				ObjectFile=".\output\pjlib-i386-win32-vc8-debug/"
+				ProgramDataBaseFileName=".\output\pjlib-i386-win32-vc8-debug/"
 				BrowseInformation="1"
 				WarningLevel="4"
@@ -70,5 +70,5 @@
 			<Tool
 				Name="VCLibrarianTool"
-				OutputFile="../lib/pjlib-i386-win32-vc6-debug.lib"
+				OutputFile="../lib/pjlib-i386-win32-vc8-debug.lib"
 				SuppressStartupBanner="true"
 			/>
@@ -82,5 +82,5 @@
 				Name="VCBscMakeTool"
 				SuppressStartupBanner="true"
-				OutputFile=".\output\pjlib-i386-win32-vc6-debug/pjlib.bsc"
+				OutputFile=".\output\pjlib-i386-win32-vc8-debug/pjlib.bsc"
 			/>
 			<Tool
@@ -93,6 +93,6 @@
 		<Configuration
 			Name="Release|Win32"
-			OutputDirectory=".\output\pjlib-i386-win32-vc6-release"
-			IntermediateDirectory=".\output\pjlib-i386-win32-vc6-release"
+			OutputDirectory=".\output\pjlib-i386-win32-vc8-release"
+			IntermediateDirectory=".\output\pjlib-i386-win32-vc8-release"
 			ConfigurationType="4"
 			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
@@ -125,8 +125,8 @@
 				RuntimeLibrary="2"
 				EnableFunctionLevelLinking="true"
-				PrecompiledHeaderFile=".\output\pjlib-i386-win32-vc6-release/pjlib.pch"
-				AssemblerListingLocation=".\output\pjlib-i386-win32-vc6-release/"
-				ObjectFile=".\output\pjlib-i386-win32-vc6-release/"
-				ProgramDataBaseFileName=".\output\pjlib-i386-win32-vc6-release/"
+				PrecompiledHeaderFile=".\output\pjlib-i386-win32-vc8-release/pjlib.pch"
+				AssemblerListingLocation=".\output\pjlib-i386-win32-vc8-release/"
+				ObjectFile=".\output\pjlib-i386-win32-vc8-release/"
+				ProgramDataBaseFileName=".\output\pjlib-i386-win32-vc8-release/"
 				BrowseInformation="1"
 				WarningLevel="4"
@@ -147,5 +147,5 @@
 			<Tool
 				Name="VCLibrarianTool"
-				OutputFile="../lib/pjlib-i386-win32-vc6-release.lib"
+				OutputFile="../lib/pjlib-i386-win32-vc8-release.lib"
 				SuppressStartupBanner="true"
 			/>
@@ -159,5 +159,5 @@
 				Name="VCBscMakeTool"
 				SuppressStartupBanner="true"
-				OutputFile=".\output\pjlib-i386-win32-vc6-release/pjlib.bsc"
+				OutputFile=".\output\pjlib-i386-win32-vc8-release/pjlib.bsc"
 			/>
 			<Tool
@@ -539,4 +539,8 @@
 			</File>
 			<File
+				RelativePath="..\src\pj\ip_helper_win32.c"
+				>
+			</File>
+			<File
 				RelativePath="..\src\pj\list.c"
 				>
@@ -1118,4 +1122,24 @@
 							AdditionalIncludeDirectories=""
 							PreprocessorDefinitions=""
+						/>
+					</FileConfiguration>
+				</File>
+				<File
+					RelativePath="..\src\pj\ip_helper_generic.c"
+					>
+					<FileConfiguration
+						Name="Debug|Win32"
+						ExcludedFromBuild="true"
+						>
+						<Tool
+							Name="VCCLCompilerTool"
+						/>
+					</FileConfiguration>
+					<FileConfiguration
+						Name="Release|Win32"
+						ExcludedFromBuild="true"
+						>
+						<Tool
+							Name="VCCLCompilerTool"
 						/>
 					</FileConfiguration>
@@ -1460,4 +1484,8 @@
 			</File>
 			<File
+				RelativePath="..\include\pj\ip_helper.h"
+				>
+			</File>
+			<File
 				RelativePath="..\include\pj\list.h"
 				>
Index: /pjproject/trunk/pjlib/include/pj/ip_helper.h
===================================================================
--- /pjproject/trunk/pjlib/include/pj/ip_helper.h	(revision 1104)
+++ /pjproject/trunk/pjlib/include/pj/ip_helper.h	(revision 1104)
@@ -0,0 +1,88 @@
+/* $Id$ */
+/* 
+ * Copyright (C)2003-2007 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#ifndef __PJ_IP_ROUTE_H__
+#define __PJ_IP_ROUTE_H__
+
+/**
+ * @file ip_helper.h
+ * @brief IP helper API
+ */
+
+#include <pj/sock.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup pj_ip_helper IP Interface and Routing Helper
+ * @ingroup PJ_IO
+ * @{
+ *
+ * This module provides functions to query local host's IP interface and 
+ * routing table.
+ */
+
+/**
+ * This structure describes IP routing entry.
+ */
+typedef union pj_ip_route_entry
+{
+    /** IP routing entry for IP version 4 routing */
+    struct
+    {
+	pj_in_addr	if_addr;    /**< Local interface IP address.	*/
+	pj_in_addr	dst_addr;   /**< Destination IP address.	*/
+	pj_in_addr	mask;	    /**< Destination mask.		*/
+    } ipv4;
+} pj_ip_route_entry;
+
+
+/**
+ * Enumerate the local IP interface currently active in the host.
+ *
+ * @param count	    On input, specify the number of entries. On output,
+ *		    it will be filled with the actual number of entries.
+ * @param ifs	    Array of IP addresses.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_enum_ip_interface(unsigned *count,
+					  pj_in_addr ifs[]);
+
+
+/**
+ * Enumerate the IP routing table for this host.
+ *
+ * @param count	    On input, specify the number of routes entries. On output,
+ *		    it will be filled with the actual number of route entries.
+ * @param routes    Array of IP routing entries.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_enum_ip_route(unsigned *count,
+				      pj_ip_route_entry routes[]);
+
+
+
+/** @} */
+
+PJ_END_DECL
+
+
+#endif	/* __PJ_IP_ROUTE_H__ */
+
Index: /pjproject/trunk/pjlib/include/pj/sock.h
===================================================================
--- /pjproject/trunk/pjlib/include/pj/sock.h	(revision 1103)
+++ /pjproject/trunk/pjlib/include/pj/sock.h	(revision 1104)
@@ -208,4 +208,5 @@
 };
 
+#undef s6_addr
 
 /**
Index: /pjproject/trunk/pjlib/include/pjlib.h
===================================================================
--- /pjproject/trunk/pjlib/include/pjlib.h	(revision 1103)
+++ /pjproject/trunk/pjlib/include/pjlib.h	(revision 1104)
@@ -38,4 +38,5 @@
 #include <pj/hash.h>
 #include <pj/ioqueue.h>
+#include <pj/ip_helper.h>
 #include <pj/list.h>
 #include <pj/lock.h>
Index: /pjproject/trunk/pjlib/src/pj/ip_helper_generic.c
===================================================================
--- /pjproject/trunk/pjlib/src/pj/ip_helper_generic.c	(revision 1104)
+++ /pjproject/trunk/pjlib/src/pj/ip_helper_generic.c	(revision 1104)
@@ -0,0 +1,69 @@
+/* $Id$ */
+/* 
+ * Copyright (C)2003-2007 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pj/ip_helper.h>
+#include <pj/addr_resolv.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/string.h>
+
+/*
+ * Enumerate the local IP interface currently active in the host.
+ */
+PJ_DEF(pj_status_t) pj_enum_ip_interface(unsigned *p_cnt,
+					 pj_in_addr ifs[])
+{
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(p_cnt && *p_cnt > 0 && ifs, PJ_EINVAL);
+
+    pj_bzero(ifs, sizeof(ifs[0]) * (*p_cnt));
+
+    /* Just get one default route */
+    status = pj_gethostip(&ifs[0]);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    *p_cnt = 1;
+    return PJ_SUCCESS;
+}
+
+/*
+ * Enumerate the IP routing table for this host.
+ */
+PJ_DEF(pj_status_t) pj_enum_ip_route(unsigned *p_cnt,
+				     pj_ip_route_entry routes[])
+{
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(p_cnt && *p_cnt > 0 && routes, PJ_EINVAL);
+
+    pj_bzero(routes, sizeof(routes[0]) * (*p_cnt));
+
+    /* Just get one default route */
+    status = pj_gethostip(&routes[0].ipv4.if_addr);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    routes[0].ipv4.dst_addr.s_addr = 0;
+    routes[0].ipv4.mask.s_addr = 0;
+    *p_cnt = 1;
+
+    return PJ_SUCCESS;
+}
+
Index: /pjproject/trunk/pjlib/src/pj/ip_helper_win32.c
===================================================================
--- /pjproject/trunk/pjlib/src/pj/ip_helper_win32.c	(revision 1104)
+++ /pjproject/trunk/pjlib/src/pj/ip_helper_win32.c	(revision 1104)
@@ -0,0 +1,136 @@
+/* $Id$ */
+/* 
+ * Copyright (C)2003-2007 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+/* PMIB_ICMP_EX is not declared in VC6, causing error */
+#if defined(_MSC_VER) && _MSC_VER < 1400
+#   define PMIB_ICMP_EX void*
+#endif
+#include <Iphlpapi.h>
+
+#include <pj/ip_helper.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/string.h>
+
+
+/*
+ * Enumerate the local IP interface currently active in the host.
+ */
+PJ_DEF(pj_status_t) pj_enum_ip_interface(unsigned *p_cnt,
+					 pj_in_addr ifs[])
+{
+    /* Provide enough buffer or otherwise it will fail with 
+     * error 22 ("Not Enough Buffer") error.
+     */
+    MIB_IPADDRTABLE ipTabBuff[4];
+    MIB_IPADDRTABLE *pTab;
+    ULONG tabSize;
+    unsigned i, count;
+    DWORD rc;
+
+    PJ_ASSERT_RETURN(p_cnt && ifs, PJ_EINVAL);
+
+    pTab = ipTabBuff;
+
+    /* Get IP address table */
+    tabSize = sizeof(ipTabBuff);
+    rc = GetIpAddrTable(ipTabBuff, &tabSize, FALSE);
+    if (rc != NO_ERROR)
+	return PJ_RETURN_OS_ERROR(rc);
+
+    /* Reset result */
+    pj_bzero(ifs, sizeof(ifs[0]) * (*p_cnt));
+
+    /* Now fill out the entries */
+    count = (pTab->dwNumEntries < *p_cnt) ? pTab->dwNumEntries : *p_cnt;
+    for (i=0; i<count; ++i) {
+	ifs[i].s_addr = pTab->table[i].dwAddr;
+    }
+
+    *p_cnt = count;
+
+    return PJ_SUCCESS;
+
+}
+
+
+/*
+ * Enumerate the IP routing table for this host.
+ */
+PJ_DEF(pj_status_t) pj_enum_ip_route(unsigned *p_cnt,
+				     pj_ip_route_entry routes[])
+{
+    MIB_IPADDRTABLE ipTabBuff[4];
+    MIB_IPADDRTABLE *pIpTab;
+    MIB_IPFORWARDTABLE rtabBuff[4];
+    MIB_IPFORWARDTABLE *prTab;
+    ULONG tabSize;
+    unsigned i, count;
+    DWORD rc;
+
+    PJ_ASSERT_RETURN(p_cnt && routes, PJ_EINVAL);
+
+    pIpTab = ipTabBuff;
+    prTab = rtabBuff;
+
+    /* First get IP address table */
+    tabSize = sizeof(ipTabBuff);
+    rc = GetIpAddrTable(ipTabBuff, &tabSize, FALSE);
+    if (rc != NO_ERROR)
+	return PJ_RETURN_OS_ERROR(rc);
+
+    /* Next get IP route table */
+    tabSize = sizeof(rtabBuff);
+    rc = GetIpForwardTable(rtabBuff, &tabSize, 1);
+    if (rc != NO_ERROR)
+	return PJ_RETURN_OS_ERROR(rc);
+
+    /* Reset routes */
+    pj_bzero(routes, sizeof(routes[0]) * (*p_cnt));
+
+    /* Now fill out the route entries */
+    count = (prTab->dwNumEntries < *p_cnt) ? prTab->dwNumEntries : *p_cnt;
+    *p_cnt = 0;
+    for (i=0; i<count; ++i) {
+	unsigned j;
+
+	/* Find interface entry */
+	for (j=0; j<pIpTab->dwNumEntries; ++j) {
+	    if (pIpTab->table[j].dwIndex == prTab->table[i].dwForwardIfIndex)
+		break;
+	}
+
+	if (j==pIpTab->dwNumEntries)
+	    continue;	/* Interface not found */
+
+	routes[*p_cnt].ipv4.if_addr.s_addr = pIpTab->table[j].dwAddr;
+	routes[*p_cnt].ipv4.dst_addr.s_addr = prTab->table[i].dwForwardDest;
+	routes[*p_cnt].ipv4.mask.s_addr = prTab->table[i].dwForwardMask;
+
+	(*p_cnt)++;
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+
Index: /pjproject/trunk/pjmedia/include/pjmedia/transport_ice.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/transport_ice.h	(revision 1103)
+++ /pjproject/trunk/pjmedia/include/pjmedia/transport_ice.h	(revision 1104)
@@ -47,6 +47,14 @@
 PJ_DECL(pj_status_t) pjmedia_ice_destroy(pjmedia_transport *tp);
 
-PJ_DECL(pj_ice_st*) pjmedia_ice_get_ice_st(pjmedia_transport *tp);
+PJ_DECL(pj_status_t) pjmedia_ice_start_init(pjmedia_transport *tp,
+					    unsigned options,
+					    const pj_sockaddr_in *start_addr,
+					    const pj_sockaddr_in *stun_srv,
+					    const pj_sockaddr_in *turn_srv);
+PJ_DECL(pj_status_t) pjmedia_ice_get_init_status(pjmedia_transport *tp);
 
+PJ_DECL(pj_status_t) pjmedia_ice_get_comp(pjmedia_transport *tp,
+					  unsigned comp_id,
+					  pj_ice_st_comp *comp);
 
 PJ_DECL(pj_status_t) pjmedia_ice_init_ice(pjmedia_transport *tp,
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 1103)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 1104)
@@ -70,6 +70,5 @@
  * And these are ICE callbacks.
  */
-static void ice_on_rx_data(pj_ice_st *ice_st,
-			   unsigned comp_id, unsigned cand_id,
+static void ice_on_rx_data(pj_ice_st *ice_st, unsigned comp_id, 
 			   void *pkt, pj_size_t size,
 			   const pj_sockaddr_t *src_addr,
@@ -100,5 +99,4 @@
     pj_ice_st_cb ice_st_cb;
     struct transport_ice *tp_ice;
-    unsigned i;
     pj_status_t status;
 
@@ -111,14 +109,9 @@
 
     /* Create ICE */
-    status = pj_ice_st_create(stun_cfg, name, NULL, &ice_st_cb, &ice_st);
+    status = pj_ice_st_create(stun_cfg, name, comp_cnt, NULL, 
+			      &ice_st_cb, &ice_st);
     if (status != PJ_SUCCESS)
 	return status;
 
-    /* Add components */
-    for (i=0; i<comp_cnt; ++i) {
-	status = pj_ice_st_add_comp(ice_st, i+1);
-	if (status != PJ_SUCCESS) 
-	    goto on_error;
-    }
 
     /* Create transport instance and attach to ICE */
@@ -136,8 +129,4 @@
 
     return PJ_SUCCESS;
-
-on_error:
-    pj_ice_st_destroy(ice_st);
-    return status;
 }
 
@@ -158,5 +147,63 @@
 
 
-PJ_DECL(pj_ice_st*) pjmedia_ice_get_ice_st(pjmedia_transport *tp)
+PJ_DEF(pj_status_t) pjmedia_ice_start_init( pjmedia_transport *tp,
+					    unsigned options,
+					    const pj_sockaddr_in *start_addr,
+					    const pj_sockaddr_in *stun_srv,
+					    const pj_sockaddr_in *turn_srv)
+{
+    struct transport_ice *tp_ice = (struct transport_ice*)tp;
+    unsigned comp_id;
+    pj_status_t status;
+
+    status = pj_ice_st_set_stun_srv(tp_ice->ice_st, stun_srv, turn_srv);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    status = pj_ice_st_create_comp(tp_ice->ice_st, 1, options, start_addr, 
+				   &comp_id);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    if (tp_ice->ice_st->comp_cnt > 1) {
+	pj_sockaddr_in addr;
+
+	pj_memcpy(&addr, &tp_ice->ice_st->comp[0]->local_addr.ipv4,
+		  sizeof(pj_sockaddr_in));
+	if (start_addr)
+	    addr.sin_addr.s_addr = start_addr->sin_addr.s_addr;
+	else
+	    addr.sin_addr.s_addr = 0;
+
+	addr.sin_port = (pj_uint16_t)(pj_ntohs(addr.sin_port)+1);
+	status = pj_ice_st_create_comp(tp_ice->ice_st, 2, options, 
+				       &addr, &comp_id);
+	if (status != PJ_SUCCESS)
+	    return status;
+    }
+    return status;
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_ice_get_init_status(pjmedia_transport *tp)
+{
+    struct transport_ice *tp_ice = (struct transport_ice*)tp;
+    return pj_ice_st_get_comps_status(tp_ice->ice_st);
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_ice_get_comp( pjmedia_transport *tp,
+					  unsigned comp_id,
+					  pj_ice_st_comp *comp)
+{
+    struct transport_ice *tp_ice = (struct transport_ice*)tp;
+    PJ_ASSERT_RETURN(tp && comp_id && comp_id <= tp_ice->ice_st->comp_cnt &&
+		     comp, PJ_EINVAL);
+
+    pj_memcpy(comp, tp_ice->ice_st->comp[comp_id-1], sizeof(pj_ice_st_comp));
+    return PJ_SUCCESS;		    
+}
+
+PJ_DEF(pj_ice_st*) pjmedia_ice_get_ice_st(pjmedia_transport *tp)
 {
     struct transport_ice *tp_ice = (struct transport_ice*)tp;
@@ -416,32 +463,28 @@
 {
     struct transport_ice *tp_ice = (struct transport_ice*)tp;
-    int rel_idx = -1, srflx_idx = -1, host_idx = -1, idx = -1;
-    unsigned i;
+    pj_ice_st *ice_st = tp_ice->ice_st;
+    pj_ice_st_comp *comp;
 
     pj_bzero(info, sizeof(*info));
     info->rtp_sock = info->rtcp_sock = PJ_INVALID_SOCKET;
 
-    for (i=0; i<tp_ice->ice_st->itf_cnt; ++i) {
-	pj_ice_st_interface *itf = tp_ice->ice_st->itfs[i];
-
-	if (itf->type == PJ_ICE_CAND_TYPE_HOST && host_idx == -1)
-	    host_idx = i;
-	else if (itf->type == PJ_ICE_CAND_TYPE_RELAYED && rel_idx == -1)
-	    rel_idx = i;
-	else if (itf->type == PJ_ICE_CAND_TYPE_SRFLX && srflx_idx == -1)
-	    srflx_idx = i;
-    }
-
-    if (idx == -1 && srflx_idx != -1)
-	idx = srflx_idx;
-    else if (idx == -1 && rel_idx != -1)
-	idx = rel_idx;
-    else if (idx == -1 && host_idx != -1)
-	idx = host_idx;
-
-    PJ_ASSERT_RETURN(idx != -1, PJ_EBUG);
-
-    pj_memcpy(&info->rtp_addr_name, &tp_ice->ice_st->itfs[idx]->addr,
+    /* Retrieve address of default candidate for component 1 (RTP) */
+    comp = ice_st->comp[0];
+    pj_assert(comp->default_cand >= 0);
+    info->rtp_sock = comp->sock;
+    pj_memcpy(&info->rtp_addr_name, 
+	      &comp->cand_list[comp->default_cand].addr,
 	      sizeof(pj_sockaddr_in));
+
+    /* Retrieve address of default candidate for component 12(RTCP) */
+    if (ice_st->comp_cnt > 1) {
+	comp = ice_st->comp[1];
+	pj_assert(comp->default_cand >= 0);
+	info->rtp_sock = comp->sock;
+	pj_memcpy(&info->rtp_addr_name, 
+		  &comp->cand_list[comp->default_cand].addr,
+		  sizeof(pj_sockaddr_in));
+    }
+
 
     return PJ_SUCCESS;
@@ -492,11 +535,7 @@
 {
     struct transport_ice *tp_ice = (struct transport_ice*)tp;
-    if (tp_ice->ice_st->ice) {
-	return pj_ice_st_send_data(tp_ice->ice_st, 1, pkt, size);
-    } else {
-	return pj_ice_st_sendto(tp_ice->ice_st, 1, 0,
-				pkt, size, &tp_ice->remote_rtp,
-				sizeof(pj_sockaddr_in));
-    }
+    return pj_ice_st_sendto(tp_ice->ice_st, 1, 
+			    pkt, size, &tp_ice->remote_rtp,
+			    sizeof(pj_sockaddr_in));
 }
 
@@ -506,19 +545,16 @@
 			        pj_size_t size)
 {
-#if 0
-    struct transport_ice *tp_ice = (struct transport_ice*)tp;
-    return pj_ice_st_send_data(tp_ice->ice_st, 1, pkt, size);
-#else
-    PJ_TODO(SUPPORT_RTCP);
-    PJ_UNUSED_ARG(tp);
-    PJ_UNUSED_ARG(pkt);
-    PJ_UNUSED_ARG(size);
-    return PJ_SUCCESS;
-#endif
-}
-
-
-static void ice_on_rx_data(pj_ice_st *ice_st,
-			   unsigned comp_id, unsigned cand_id,
+    struct transport_ice *tp_ice = (struct transport_ice*)tp;
+    if (tp_ice->ice_st->comp_cnt > 1) {
+	return pj_ice_st_sendto(tp_ice->ice_st, 2, 
+				pkt, size, &tp_ice->remote_rtp,
+				sizeof(pj_sockaddr_in));
+    } else {
+	return PJ_SUCCESS;
+    }
+}
+
+
+static void ice_on_rx_data(pj_ice_st *ice_st, unsigned comp_id, 
 			   void *pkt, pj_size_t size,
 			   const pj_sockaddr_t *src_addr,
@@ -532,7 +568,8 @@
 	(*tp_ice->rtcp_cb)(tp_ice->stream, pkt, size);
 
-    PJ_UNUSED_ARG(cand_id);
     PJ_UNUSED_ARG(src_addr);
     PJ_UNUSED_ARG(src_addr_len);
+
+    PJ_TODO(SWITCH_SOURCE_ADDRESS);
 }
 
Index: /pjproject/trunk/pjnath/include/pjnath/ice.h
===================================================================
--- /pjproject/trunk/pjnath/include/pjnath/ice.h	(revision 1103)
+++ /pjproject/trunk/pjnath/include/pjnath/ice.h	(revision 1104)
@@ -151,5 +151,4 @@
 			     unsigned dst_addr_len);
     void	(*on_rx_data)(pj_ice *ice, unsigned comp_id,
-			      unsigned cand_id,
 			      void *pkt, pj_size_t size,
 			      const pj_sockaddr_t *src_addr,
Index: /pjproject/trunk/pjnath/include/pjnath/ice_stream_transport.h
===================================================================
--- /pjproject/trunk/pjnath/include/pjnath/ice_stream_transport.h	(revision 1103)
+++ /pjproject/trunk/pjnath/include/pjnath/ice_stream_transport.h	(revision 1104)
@@ -45,5 +45,5 @@
 {
     void    (*on_rx_data)(pj_ice_st *ice_st,
-			  unsigned comp_id, unsigned cand_id,
+			  unsigned comp_id, 
 			  void *pkt, pj_size_t size,
 			  const pj_sockaddr_t *src_addr,
@@ -55,22 +55,45 @@
 
 
+#ifndef PJ_ICE_ST_MAX_ALIASES
+#   define PJ_ICE_ST_MAX_ALIASES	8
+#endif
+
+enum pj_ice_st_option
+{
+    PJ_ICE_ST_OPT_DISABLE_STUN	= 1,
+    PJ_ICE_ST_OPT_DISABLE_RELAY	= 2,
+    PJ_ICE_ST_OPT_NO_PORT_RETRY	= 4,
+};
+
+
+typedef struct pj_ice_st_cand
+{
+    pj_ice_cand_type	type;
+    pj_status_t		status;
+    pj_sockaddr		addr;
+    int			cand_id;
+    pj_uint16_t		local_pref;
+    pj_str_t		foundation;
+} pj_ice_st_cand;
+
+
 typedef struct pj_ice_st_comp
 {
+    pj_ice_st		*ice_st;
     unsigned		 comp_id;
-} pj_ice_st_comp;
+    pj_uint32_t		 options;
+    pj_sock_t		 sock;
 
+    pj_stun_session	*stun_sess;
 
-typedef struct pj_ice_st_interface
-{
-    pj_ice_st		*ice_st;
-    pj_ice_cand_type	 type;
-    pj_status_t		 status;
-    unsigned		 comp_id;
-    int			 cand_id;
-    pj_str_t		 foundation;
-    pj_uint16_t		 local_pref;
-    pj_sock_t		 sock;
-    pj_sockaddr		 addr;
-    pj_sockaddr		 base_addr;
+    pj_sockaddr		 local_addr;
+
+    unsigned		 pending_cnt;
+    pj_status_t		 last_status;
+
+    unsigned		 cand_cnt;
+    pj_ice_st_cand	 cand_list[PJ_ICE_ST_MAX_ALIASES];
+    int			 default_cand;
+
     pj_ioqueue_key_t	*key;
     pj_uint8_t		 pkt[1500];
@@ -79,6 +102,6 @@
     pj_sockaddr		 src_addr;
     int			 src_addr_len;
-    pj_stun_session	*stun_sess;
-} pj_ice_st_interface;
+
+} pj_ice_st_comp;
 
 
@@ -94,13 +117,10 @@
 
     unsigned		     comp_cnt;
-    unsigned		     comps[PJ_ICE_MAX_COMP];
-
-    unsigned		     itf_cnt;
-    pj_ice_st_interface	    *itfs[PJ_ICE_MAX_CAND];
+    pj_ice_st_comp	   **comp;
 
     pj_dns_resolver	    *resolver;
-    pj_bool_t		     relay_enabled;
-    pj_str_t		     stun_domain;
+    pj_bool_t		     has_resolver_job;
     pj_sockaddr_in	     stun_srv;
+    pj_sockaddr_in	     turn_srv;
 };
 
@@ -108,4 +128,5 @@
 PJ_DECL(pj_status_t) pj_ice_st_create(pj_stun_config *stun_cfg,
 				      const char *name,
+				      unsigned comp_cnt,
 				      void *user_data,
 				      const pj_ice_st_cb *cb,
@@ -113,33 +134,18 @@
 PJ_DECL(pj_status_t) pj_ice_st_destroy(pj_ice_st *ice_st);
 
-PJ_DECL(pj_status_t) pj_ice_st_set_stun(pj_ice_st *ice_st,
-					pj_dns_resolver *resolver,
-					pj_bool_t enable_relay,
-					const pj_str_t *domain);
-PJ_DECL(pj_status_t) pj_ice_st_set_stun_addr(pj_ice_st *ice_st,
-					     pj_bool_t enable_relay,
-					     const pj_sockaddr_in *srv_addr);
+PJ_DECL(pj_status_t) pj_ice_st_set_stun_domain(pj_ice_st *ice_st,
+					       pj_dns_resolver *resolver,
+					       const pj_str_t *domain);
+PJ_DECL(pj_status_t) pj_ice_st_set_stun_srv(pj_ice_st *ice_st,
+					    const pj_sockaddr_in *stun_srv,
+					    const pj_sockaddr_in *turn_srv);
 
-PJ_DECL(pj_status_t) pj_ice_st_add_comp(pj_ice_st *ice_st,
-					unsigned comp_id);
+PJ_DECL(pj_status_t) pj_ice_st_create_comp(pj_ice_st *ice_st,
+					   unsigned comp_id,
+					   pj_uint32_t options,
+					   const pj_sockaddr_in *addr,
+				    	   unsigned *p_itf_id);
 
-PJ_DECL(pj_status_t) pj_ice_st_add_host_interface(pj_ice_st *ice_st,
-						  unsigned comp_id,
-						  pj_uint16_t local_pref,
-					          const pj_sockaddr_in *addr,
-				    		  unsigned *p_itf_id);
-PJ_DECL(pj_status_t) pj_ice_st_add_all_host_interfaces(pj_ice_st *ice_st,
-						       unsigned comp_id,
-						       unsigned port);
-PJ_DECL(pj_status_t) pj_ice_st_add_stun_interface(pj_ice_st *ice_st,
-						  unsigned comp_id,
-						  unsigned local_port,
-						  unsigned *p_itf_id);
-PJ_DECL(pj_status_t) pj_ice_st_add_relay_interface(pj_ice_st *ice_st,
-						   unsigned comp_id,
-						   unsigned local_port,
-						   pj_bool_t notify,
-						   void *notify_data);
-PJ_DECL(pj_status_t) pj_ice_st_get_interfaces_status(pj_ice_st *ice_st);
+PJ_DECL(pj_status_t) pj_ice_st_get_comps_status(pj_ice_st *ice_st);
 
 PJ_DECL(pj_status_t) pj_ice_st_init_ice(pj_ice_st *ice_st,
@@ -157,11 +163,6 @@
 PJ_DECL(pj_status_t) pj_ice_st_stop_ice(pj_ice_st *ice_st);
 
-PJ_DECL(pj_status_t) pj_ice_st_send_data(pj_ice_st *ice_st,
-					 unsigned comp_id,
-					 const void *data,
-					 pj_size_t data_len);
 PJ_DECL(pj_status_t) pj_ice_st_sendto(pj_ice_st *ice_st,
 				      unsigned comp_id,
-				      unsigned itf_id,
 				      const void *data,
 				      pj_size_t data_len,
Index: /pjproject/trunk/pjnath/src/pjnath/ice.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/ice.c	(revision 1103)
+++ /pjproject/trunk/pjnath/src/pjnath/ice.c	(revision 1104)
@@ -1710,5 +1710,5 @@
 					   NULL, src_addr, src_addr_len);
     } else {
-	(*ice->cb.on_rx_data)(ice, comp_id, cand_id, pkt, pkt_size, 
+	(*ice->cb.on_rx_data)(ice, comp_id, pkt, pkt_size, 
 			      src_addr, src_addr_len);
     }
Index: /pjproject/trunk/pjnath/src/pjnath/ice_stream_transport.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/ice_stream_transport.c	(revision 1103)
+++ /pjproject/trunk/pjnath/src/pjnath/ice_stream_transport.c	(revision 1104)
@@ -21,4 +21,5 @@
 #include <pj/addr_resolv.h>
 #include <pj/assert.h>
+#include <pj/ip_helper.h>
 #include <pj/log.h>
 #include <pj/pool.h>
@@ -29,11 +30,11 @@
 /* ICE callbacks */
 static void	   on_ice_complete(pj_ice *ice, pj_status_t status);
-static pj_status_t on_tx_pkt(pj_ice *ice, 
-			     unsigned comp_id, unsigned cand_id,
-			     const void *pkt, pj_size_t size,
-			     const pj_sockaddr_t *dst_addr,
-			     unsigned dst_addr_len);
-static void	   on_rx_data(pj_ice *ice, 
+static pj_status_t ice_tx_pkt(pj_ice *ice, 
 			      unsigned comp_id, unsigned cand_id,
+			      const void *pkt, pj_size_t size,
+			      const pj_sockaddr_t *dst_addr,
+			      unsigned dst_addr_len);
+static void	   ice_rx_data(pj_ice *ice, 
+			      unsigned comp_id, 
 			      void *pkt, pj_size_t size,
 			      const pj_sockaddr_t *src_addr,
@@ -45,5 +46,5 @@
                              pj_ssize_t bytes_read);
 
-static void destroy_ice_interface(pj_ice_st_interface *is);
+static void destroy_component(pj_ice_st_comp *comp);
 static void destroy_ice_st(pj_ice_st *ice_st, pj_status_t reason);
 
@@ -86,165 +87,9 @@
 
 /* 
- * Create new interface (i.e. socket) 
- */
-static pj_status_t create_ice_interface(pj_ice_st *ice_st,
-					pj_ice_cand_type type,
-					unsigned comp_id,
-					pj_uint16_t local_pref,
-					const pj_sockaddr_in *addr,
-					pj_ice_st_interface **p_is)
-{
-    pj_ioqueue_callback ioqueue_cb;
-    pj_ice_st_interface *is;
-    char foundation[32];
-    int addr_len;
-    pj_status_t status;
-
-    is = PJ_POOL_ZALLOC_T(ice_st->pool, pj_ice_st_interface);
-    is->type = type;
-    is->comp_id = comp_id;
-    is->cand_id = -1;
-    is->sock = PJ_INVALID_SOCKET;
-    is->ice_st = ice_st;
-    is->local_pref = local_pref;
-
-    status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &is->sock);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* Bind and get the local IP address */
-    if (addr) 
-	pj_memcpy(&is->base_addr, addr, sizeof(pj_sockaddr_in));
-    else 
-	pj_sockaddr_in_init(&is->base_addr.ipv4, NULL, 0);
-
-    status = pj_sock_bind(is->sock, &is->base_addr, sizeof(pj_sockaddr_in));
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-    addr_len = sizeof(is->base_addr);
-    status = pj_sock_getsockname(is->sock, &is->base_addr, &addr_len);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-    if (is->base_addr.ipv4.sin_addr.s_addr == 0) {
-	status = pj_gethostip(&is->base_addr.ipv4.sin_addr);
-	if (status != PJ_SUCCESS) 
-	    goto on_error;
-    }
-
-    /* Assign foundation */
-    pj_ansi_snprintf(foundation, sizeof(foundation), "%c%x", 
-		     get_type_prefix(type),
-		     (int)pj_ntohl(is->base_addr.ipv4.sin_addr.s_addr));
-    pj_strdup2(ice_st->pool, &is->foundation, foundation);
-
-
-    /* Register to ioqueue */
-    pj_bzero(&ioqueue_cb, sizeof(ioqueue_cb));
-    ioqueue_cb.on_read_complete = &on_read_complete;
-    status = pj_ioqueue_register_sock(ice_st->pool, ice_st->stun_cfg.ioqueue, 
-				      is->sock, is, &ioqueue_cb, &is->key);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-    pj_ioqueue_op_key_init(&is->read_op, sizeof(is->read_op));
-    pj_ioqueue_op_key_init(&is->write_op, sizeof(is->write_op));
-
-    /* Kick start reading the socket */
-    on_read_complete(is->key, &is->read_op, 0);
-
-    /* Done */
-    *p_is = is;
-    return PJ_SUCCESS;
-
-on_error:
-    destroy_ice_interface(is);
-    return status;
-}
-
-/* 
- * This is callback called by ioqueue on incoming packet 
- */
-static void on_read_complete(pj_ioqueue_key_t *key, 
-                             pj_ioqueue_op_key_t *op_key, 
-                             pj_ssize_t bytes_read)
-{
-    pj_ice_st_interface *is = (pj_ice_st_interface*) 
-			      pj_ioqueue_get_user_data(key);
-    pj_ice_st *ice_st = is->ice_st;
-    pj_ssize_t pkt_size;
-    pj_status_t status;
-
-    if (bytes_read > 0) {
-
-	/* If we have an active ICE session, hand over all incoming
-	 * packets to the ICE session. Otherwise just drop the packet.
-	 */
-	if (ice_st->ice) {
-	    status = pj_ice_on_rx_pkt(ice_st->ice, 
-				      is->comp_id, is->cand_id,
-				      is->pkt, bytes_read,
-				      &is->src_addr, is->src_addr_len);
-	} else if (is->stun_sess) {
-	    status = pj_stun_msg_check(is->pkt, bytes_read, PJ_STUN_IS_DATAGRAM);
-	    if (status == PJ_SUCCESS) {
-		status = pj_stun_session_on_rx_pkt(is->stun_sess, is->pkt, 
-						   bytes_read, 
-						   PJ_STUN_IS_DATAGRAM, NULL,
-						   &is->src_addr, 
-						   is->src_addr_len);
-	    } else {
-		(*ice_st->cb.on_rx_data)(ice_st, is->comp_id, is->cand_id, 
-					 is->pkt, bytes_read, 
-					 &is->src_addr, is->src_addr_len);
-
-	    }
-	} else {
-	    (*ice_st->cb.on_rx_data)(ice_st, is->comp_id, is->cand_id, 
-				     is->pkt, bytes_read, 
-				     &is->src_addr, is->src_addr_len);
-	}
-
-    } else if (bytes_read < 0) {
-	ice_st_perror(is->ice_st, "ioqueue read callback error", -bytes_read);
-    }
-
-    /* Read next packet */
-    pkt_size = sizeof(is->pkt);
-    is->src_addr_len = sizeof(is->src_addr);
-    status = pj_ioqueue_recvfrom(key, op_key, is->pkt, &pkt_size, 
-				 PJ_IOQUEUE_ALWAYS_ASYNC,
-				 &is->src_addr, &is->src_addr_len);
-    if (status != PJ_SUCCESS && status != PJ_EPENDING) {
-	ice_st_perror(is->ice_st, "ioqueue recvfrom() error", status);
-    }
-}
-
-/* 
- * Destroy an interface 
- */
-static void destroy_ice_interface(pj_ice_st_interface *is)
-{
-    if (is->stun_sess) {
-	pj_stun_session_destroy(is->stun_sess);
-	is->stun_sess = NULL;
-    }
-
-    if (is->key) {
-	pj_ioqueue_unregister(is->key);
-	is->key = NULL;
-	is->sock = PJ_INVALID_SOCKET;
-    } else if (is->sock != PJ_INVALID_SOCKET && is->sock != 0) {
-	pj_sock_close(is->sock);
-	is->sock = PJ_INVALID_SOCKET;
-    }
-}
-
-/* 
  * Create ICE stream transport 
  */
 PJ_DECL(pj_status_t) pj_ice_st_create(pj_stun_config *stun_cfg,
 				      const char *name,
+				      unsigned comp_cnt,
 				      void *user_data,
 				      const pj_ice_st_cb *cb,
@@ -254,5 +99,5 @@
     pj_ice_st *ice_st;
 
-    PJ_ASSERT_RETURN(stun_cfg && cb && p_ice_st, PJ_EINVAL);
+    PJ_ASSERT_RETURN(stun_cfg && comp_cnt && cb && p_ice_st, PJ_EINVAL);
     PJ_ASSERT_RETURN(stun_cfg->ioqueue && stun_cfg->timer_heap, PJ_EINVAL);
 
@@ -266,7 +111,12 @@
     ice_st->user_data = user_data;
     
+    ice_st->comp_cnt = comp_cnt;
+    ice_st->comp = (pj_ice_st_comp**) pj_pool_calloc(pool, comp_cnt, 
+						     sizeof(void*));
+
     pj_memcpy(&ice_st->cb, cb, sizeof(*cb));
     pj_memcpy(&ice_st->stun_cfg, stun_cfg, sizeof(*stun_cfg));
 
+
     PJ_LOG(4,(ice_st->obj_name, "ICE stream transport created"));
 
@@ -275,4 +125,5 @@
 }
 
+/* Destroy ICE */
 static void destroy_ice_st(pj_ice_st *ice_st, pj_status_t reason)
 {
@@ -291,10 +142,12 @@
     }
 
-    /* Destroy all interfaces */
-    for (i=0; i<ice_st->itf_cnt; ++i) {
-	destroy_ice_interface(ice_st->itfs[i]);
-	ice_st->itfs[i] = NULL;
-    }
-    ice_st->itf_cnt = 0;
+    /* Destroy all components */
+    for (i=0; i<ice_st->comp_cnt; ++i) {
+	if (ice_st->comp[i]) {
+	    destroy_component(ice_st->comp[i]);
+	    ice_st->comp[i] = NULL;
+	}
+    }
+    ice_st->comp_cnt = 0;
 
     /* Done */
@@ -318,13 +171,11 @@
  * Resolve STUN server
  */
-PJ_DEF(pj_status_t) pj_ice_st_set_stun( pj_ice_st *ice_st,
-				        pj_dns_resolver *resolver,
-					pj_bool_t enable_relay,
-					const pj_str_t *domain)
+PJ_DEF(pj_status_t) pj_ice_st_set_stun_domain(pj_ice_st *ice_st,
+					      pj_dns_resolver *resolver,
+					      const pj_str_t *domain)
 {
     /* Yeah, TODO */
     PJ_UNUSED_ARG(ice_st);
     PJ_UNUSED_ARG(resolver);
-    PJ_UNUSED_ARG(enable_relay);
     PJ_UNUSED_ARG(domain);
     return -1;
@@ -334,219 +185,450 @@
  * Set STUN server address.
  */
-PJ_DEF(pj_status_t) pj_ice_st_set_stun_addr( pj_ice_st *ice_st,
-					     pj_bool_t enable_relay,
-					     const pj_sockaddr_in *srv_addr)
-{
-
-    PJ_ASSERT_RETURN(ice_st && srv_addr, PJ_EINVAL);
-    
-    ice_st->relay_enabled = enable_relay;
-    pj_strdup2(ice_st->pool, &ice_st->stun_domain,
-	       pj_inet_ntoa(srv_addr->sin_addr));
-    pj_memcpy(&ice_st->stun_srv, srv_addr, sizeof(pj_sockaddr_in));
+PJ_DEF(pj_status_t) pj_ice_st_set_stun_srv( pj_ice_st *ice_st,
+					    const pj_sockaddr_in *stun_srv,
+					    const pj_sockaddr_in *turn_srv)
+{
+    PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
+    /* Must not have pending resolver job */
+    PJ_ASSERT_RETURN(ice_st->has_resolver_job==PJ_FALSE, PJ_EINVALIDOP);
+
+    if (stun_srv) {
+	pj_memcpy(&ice_st->stun_srv, stun_srv, sizeof(pj_sockaddr_in));
+    } else {
+	pj_bzero(&ice_st->stun_srv, sizeof(pj_sockaddr_in));
+    }
+
+    if (turn_srv) {
+	pj_memcpy(&ice_st->turn_srv, turn_srv, sizeof(pj_sockaddr_in));
+    } else {
+	pj_bzero(&ice_st->turn_srv, sizeof(pj_sockaddr_in));
+    }
 
     return PJ_SUCCESS;
 }
 
-/*
- * Add new component.
- */
-PJ_DEF(pj_status_t) pj_ice_st_add_comp(pj_ice_st *ice_st,
-				       unsigned comp_id)
-{
-    /* Verify arguments */
-    PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL);
-
-    /* Can only add component when we don't have active ICE session */
-    PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EBUSY);
-
-    /* Check that we don't have too many components */
-    PJ_ASSERT_RETURN(ice_st->comp_cnt < PJ_ICE_MAX_COMP, PJ_ETOOMANY);
-
-    /* Component ID must be valid */
-    PJ_ASSERT_RETURN(comp_id <= PJ_ICE_MAX_COMP, PJNATH_EICEINCOMPID);
-
-    /* First component ID must be 1, second must be 2, etc., and 
-     * they must be registered in order.
-     */
-    PJ_ASSERT_RETURN(ice_st->comps[comp_id-1] == ice_st->comp_cnt, 
-		     PJNATH_EICEINCOMPID);
-
-    /* All in order, add the component. */
-    ice_st->comps[ice_st->comp_cnt++] = comp_id;
-
-    return PJ_SUCCESS;
-}
-
-/* Add interface */
-static void add_interface(pj_ice_st *ice_st, pj_ice_st_interface *is,
-			  unsigned *p_itf_id)
-{
-    unsigned itf_id;
-
-    itf_id = ice_st->itf_cnt++;
-    ice_st->itfs[itf_id] = is;
-
-    if (p_itf_id)
-	*p_itf_id = itf_id;
-}
-
-/*
- * Add new host interface.
- */
-PJ_DEF(pj_status_t) pj_ice_st_add_host_interface(pj_ice_st *ice_st,
-						 unsigned comp_id,
-						 pj_uint16_t local_pref,
-					         const pj_sockaddr_in *addr,
-				    		 unsigned *p_itf_id)
-{
-    pj_ice_st_interface *is;
+
+/* Calculate foundation */
+static pj_str_t calc_foundation(pj_pool_t *pool,
+				pj_ice_cand_type type,
+				const pj_in_addr *base_addr)
+{
+    char foundation[32];
+    pj_str_t result;
+
+    pj_ansi_snprintf(foundation, sizeof(foundation), "%c%x", 
+		     get_type_prefix(type),
+		     (int)pj_ntohl(base_addr->s_addr));
+    pj_strdup2(pool, &result, foundation);
+
+    return result;
+}
+
+/*  Create new component (i.e. socket)  */
+static pj_status_t create_component(pj_ice_st *ice_st,
+				    unsigned comp_id,
+				    pj_uint32_t options,
+				    const pj_sockaddr_in *addr,
+				    pj_ice_st_comp **p_comp)
+{
+    enum { MAX_RETRY=100, PORT_INC=2 };
+    pj_ioqueue_callback ioqueue_cb;
+    pj_ice_st_comp *comp;
+    int retry, addr_len;
     pj_status_t status;
 
-    /* Verify arguments */
-    PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL);
-
-    /* Check that component ID present */
-    PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJNATH_EICEINCOMPID);
-
-    /* Can't add new interface while ICE is running */
-    PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EBUSY);
-
-    /* Create interface */
-    status = create_ice_interface(ice_st, PJ_ICE_CAND_TYPE_HOST, comp_id,
-				  local_pref, addr, &is);
+    comp = PJ_POOL_ZALLOC_T(ice_st->pool, pj_ice_st_comp);
+    comp->ice_st = ice_st;
+    comp->comp_id = comp_id;
+    comp->options = options;
+    comp->sock = PJ_INVALID_SOCKET;
+    comp->last_status = PJ_SUCCESS;
+
+    /* Create socket */
+    status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &comp->sock);
     if (status != PJ_SUCCESS)
 	return status;
 
-    /* For host interface, the address is the base address */
-    pj_memcpy(&is->addr, &is->base_addr, sizeof(is->addr));
-
-    /* Store this interface */
-    add_interface(ice_st, is, p_itf_id);
-
-    /* Set interface status to SUCCESS */
-    is->status = PJ_SUCCESS;
+    /* Init address */
+    if (addr) 
+	pj_memcpy(&comp->local_addr, addr, sizeof(pj_sockaddr_in));
+    else 
+	pj_sockaddr_in_init(&comp->local_addr.ipv4, NULL, 0);
+
+    /* Retry binding socket */
+    for (retry=0; retry<MAX_RETRY; ++retry) {
+	pj_uint16_t port;
+
+	status = pj_sock_bind(comp->sock, &comp->local_addr, 
+			      sizeof(pj_sockaddr_in));
+	if (status == PJ_SUCCESS)
+	    break;
+
+	if (options & PJ_ICE_ST_OPT_NO_PORT_RETRY)
+	    goto on_error;
+
+	port = pj_ntohs(comp->local_addr.ipv4.sin_port);
+	port += PORT_INC;
+	comp->local_addr.ipv4.sin_port = pj_htons(port);
+    }
+
+    /* Get the actual port where the socket is bound to.
+     * (don't care about the address, it will be retrieved later)
+     */
+    addr_len = sizeof(comp->local_addr);
+    status = pj_sock_getsockname(comp->sock, &comp->local_addr, &addr_len);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    /* Register to ioqueue */
+    pj_bzero(&ioqueue_cb, sizeof(ioqueue_cb));
+    ioqueue_cb.on_read_complete = &on_read_complete;
+    status = pj_ioqueue_register_sock(ice_st->pool, ice_st->stun_cfg.ioqueue, 
+				      comp->sock, comp, &ioqueue_cb, 
+				      &comp->key);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    pj_ioqueue_op_key_init(&comp->read_op, sizeof(comp->read_op));
+    pj_ioqueue_op_key_init(&comp->write_op, sizeof(comp->write_op));
+
+    /* Kick start reading the socket */
+    on_read_complete(comp->key, &comp->read_op, 0);
+
+    /* If the socket is bound to INADDR_ANY, then lookup all interfaces in
+     * the host and add them into cand_list. Otherwise if the socket is bound
+     * to a specific interface, then only add that specific interface to
+     * cand_list.
+     */
+    if (comp->local_addr.ipv4.sin_addr.s_addr == 0) {
+	/* Socket is bound to INADDR_ANY */
+	unsigned i, ifs_cnt;
+	pj_in_addr ifs[PJ_ICE_ST_MAX_ALIASES-2];
+
+	/* Reset default candidate */
+	comp->default_cand = -1;
+
+	/* Enum all IP interfaces in the host */
+	ifs_cnt = PJ_ARRAY_SIZE(ifs);
+	status = pj_enum_ip_interface(&ifs_cnt, ifs);
+	if (status != PJ_SUCCESS)
+	    goto on_error;
+
+	/* Set default IP interface as the base address */
+	status = pj_gethostip(&comp->local_addr.ipv4.sin_addr);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	/* Add candidate entry for each interface */
+	for (i=0; i<ifs_cnt; ++i) {
+	    pj_ice_st_cand *cand = &comp->cand_list[i];
+
+	    cand->type = PJ_ICE_CAND_TYPE_HOST;
+	    cand->status = PJ_SUCCESS;
+	    pj_memcpy(&cand->addr, &comp->local_addr, sizeof(pj_sockaddr_in));
+	    cand->addr.ipv4.sin_addr.s_addr = ifs[i].s_addr;
+	    cand->cand_id = -1;
+	    cand->local_pref = 65535;
+	    cand->foundation = calc_foundation(ice_st->pool, 
+					     PJ_ICE_CAND_TYPE_HOST,
+					     &cand->addr.ipv4.sin_addr);
+
+	    /* If the IP address is equal to local address, assign it
+	     * as default candidate.
+	     */
+	    if (cand->addr.ipv4.sin_addr.s_addr ==
+		comp->local_addr.ipv4.sin_addr.s_addr)
+	    {
+		comp->default_cand = i;
+	    }
+
+	    PJ_LOG(5,(ice_st->obj_name, 
+		      "Interface %s:%d added to component %d",
+		      pj_inet_ntoa(cand->addr.ipv4.sin_addr),
+		      (int)pj_ntohs(cand->addr.ipv4.sin_port), comp_id));
+	}
+	comp->cand_cnt = ifs_cnt;
+
+
+    } else {
+	/* Socket is bound to specific address. 
+	 * In this case only add that address as a single entry in the
+	 * cand_list table.
+	 */
+	pj_ice_st_cand *cand = &comp->cand_list[0];
+
+	cand->type = PJ_ICE_CAND_TYPE_HOST;
+	cand->status = PJ_SUCCESS;
+	pj_memcpy(&cand->addr, &comp->local_addr, sizeof(pj_sockaddr_in));
+	cand->cand_id = -1;
+	cand->local_pref = 65535;
+	cand->foundation = calc_foundation(ice_st->pool, 
+					 PJ_ICE_CAND_TYPE_HOST,
+					 &cand->addr.ipv4.sin_addr);
+
+	comp->cand_cnt = 1;
+	comp->default_cand = 0;
+
+	PJ_LOG(5,(ice_st->obj_name, 
+		  "Interface %s:%d added to component %d",
+		  pj_inet_ntoa(cand->addr.ipv4.sin_addr),
+		  (int)pj_ntohs(cand->addr.ipv4.sin_port), comp_id));
+
+    }
+
+    /* Done */
+    if (p_comp)
+	*p_comp = comp;
 
     return PJ_SUCCESS;
-}
-
-/*
- * Enumerate and add all host interfaces.
- */
-PJ_DEF(pj_status_t) pj_ice_st_add_all_host_interfaces(pj_ice_st *ice_st,
-						      unsigned comp_id,
-						      unsigned port)
-{
-    pj_sockaddr_in addr;
+
+on_error:
+    destroy_component(comp);
+    return status;
+}
+
+/* 
+ * This is callback called by ioqueue on incoming packet 
+ */
+static void on_read_complete(pj_ioqueue_key_t *key, 
+                             pj_ioqueue_op_key_t *op_key, 
+                             pj_ssize_t bytes_read)
+{
+    pj_ice_st_comp *comp = (pj_ice_st_comp*) 
+			    pj_ioqueue_get_user_data(key);
+    pj_ice_st *ice_st = comp->ice_st;
+    pj_ssize_t pkt_size;
     pj_status_t status;
 
-    /* Yeah, TODO.
-     * For now just add the default interface.
-     */
-    pj_sockaddr_in_init(&addr, NULL, (pj_uint16_t)port);
-    
-    status = pj_gethostip(&addr.sin_addr);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    return pj_ice_st_add_host_interface(ice_st, comp_id, 65535, &addr, NULL);
-}
-
-/*
- * Add STUN mapping interface.
- */
-PJ_DEF(pj_status_t) pj_ice_st_add_stun_interface(pj_ice_st *ice_st,
-						 unsigned comp_id,
-						 unsigned local_port,
-						 unsigned *p_itf_id)
-{
-    pj_ice_st_interface *is;
-    pj_sockaddr_in local_addr;
+    if (bytes_read > 0) {
+	/*
+	 * Okay, we got a packet from the socket for the component. There is
+	 * a bit of situation here, since this packet could be one of these:
+	 *
+	 * 1) this could be the response of STUN binding request sent by
+	 *    this component to a) an initial request to get the STUN mapped
+	 *    address of this component, or b) subsequent request to keep
+	 *    the binding alive.
+	 * 
+	 * 2) this could be a packet (STUN or not STUN) sent from the STUN
+	 *    relay server. In this case, still there are few options to do
+	 *    for this packet: a) process this locally if this packet is
+	 *    related to TURN session management (e.g. Allocate response),
+	 *    b) forward this packet to ICE if this is related to ICE
+	 *    discovery process.
+	 *
+	 * 3) this could be a STUN request or response sent as part of ICE
+	 *    discovery process.
+	 *
+	 * 4) this could be application's packet, e.g. when ICE processing
+	 *    is done and agents start sending RTP/RTCP packets to each
+	 *    other, or when ICE processing is not done and this ICE stream
+	 *    transport decides to allow sending data.
+	 *
+	 * So far we don't have good solution for this.
+	 * The process below is just a workaround.
+	 */
+	if (ice_st->ice) {
+	    PJ_TODO(DISTINGUISH_BETWEEN_LOCAL_AND_RELAY);
+	    status = pj_ice_on_rx_pkt(ice_st->ice, comp->comp_id, 
+				      comp->cand_list[0].cand_id,
+				      comp->pkt, bytes_read,
+				      &comp->src_addr, comp->src_addr_len);
+	} else if (comp->stun_sess) {
+	    status = pj_stun_msg_check(comp->pkt, bytes_read, 
+				       PJ_STUN_IS_DATAGRAM);
+	    if (status == PJ_SUCCESS) {
+		status = pj_stun_session_on_rx_pkt(comp->stun_sess, comp->pkt,
+						   bytes_read, 
+						   PJ_STUN_IS_DATAGRAM, NULL,
+						   &comp->src_addr, 
+						   comp->src_addr_len);
+	    } else {
+		(*ice_st->cb.on_rx_data)(ice_st, comp->comp_id, 
+					 comp->pkt, bytes_read, 
+					 &comp->src_addr, comp->src_addr_len);
+
+	    }
+	} else {
+	    (*ice_st->cb.on_rx_data)(ice_st, comp->comp_id, 
+				     comp->pkt, bytes_read, 
+				     &comp->src_addr, comp->src_addr_len);
+	}
+
+    } else if (bytes_read < 0) {
+	ice_st_perror(comp->ice_st, "ioqueue read callback error", 
+		      -bytes_read);
+    }
+
+    /* Read next packet */
+    pkt_size = sizeof(comp->pkt);
+    comp->src_addr_len = sizeof(comp->src_addr);
+    status = pj_ioqueue_recvfrom(key, op_key, comp->pkt, &pkt_size, 
+				 PJ_IOQUEUE_ALWAYS_ASYNC,
+				 &comp->src_addr, &comp->src_addr_len);
+    if (status != PJ_SUCCESS && status != PJ_EPENDING) {
+	ice_st_perror(comp->ice_st, "ioqueue recvfrom() error", status);
+    }
+}
+
+/* 
+ * Destroy a component 
+ */
+static void destroy_component(pj_ice_st_comp *comp)
+{
+    if (comp->stun_sess) {
+	pj_stun_session_destroy(comp->stun_sess);
+	comp->stun_sess = NULL;
+    }
+
+    if (comp->key) {
+	pj_ioqueue_unregister(comp->key);
+	comp->key = NULL;
+	comp->sock = PJ_INVALID_SOCKET;
+    } else if (comp->sock != PJ_INVALID_SOCKET && comp->sock != 0) {
+	pj_sock_close(comp->sock);
+	comp->sock = PJ_INVALID_SOCKET;
+    }
+}
+
+
+
+/*
+ * Add STUN mapping to a component.
+ */
+static pj_status_t get_stun_mapped_addr(pj_ice_st *ice_st,
+					pj_ice_st_comp *comp)
+{
+    pj_ice_st_cand *cand;
     pj_stun_session_cb sess_cb;
     pj_stun_tx_data *tdata;
     pj_status_t status;
 
-    PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL);
+    PJ_ASSERT_RETURN(ice_st && comp, PJ_EINVAL);
     
-    /* STUN server must have been configured */
-    PJ_ASSERT_RETURN(ice_st->stun_srv.sin_family != 0, PJ_EINVALIDOP);
-
-
-    /* Create interface */
-    pj_sockaddr_in_init(&local_addr, NULL, (pj_uint16_t)local_port);
-    status = create_ice_interface(ice_st, PJ_ICE_CAND_TYPE_SRFLX, comp_id,
-				  65535, &local_addr, &is);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* Create STUN session */
+    /* Bail out if STUN server is still being resolved */
+    if (ice_st->has_resolver_job)
+	return PJ_EBUSY;
+
+    /* Just return (successfully) if STUN server is not configured */
+    if (ice_st->stun_srv.sin_family == 0)
+	return PJ_SUCCESS;
+
+
+    /* Create STUN session for this component */
     pj_bzero(&sess_cb, sizeof(sess_cb));
     sess_cb.on_request_complete = &stun_on_request_complete;
     sess_cb.on_send_msg = &stun_on_send_msg;
     status = pj_stun_session_create(&ice_st->stun_cfg, ice_st->obj_name,
-				    &sess_cb, PJ_FALSE, &is->stun_sess);
+				    &sess_cb, PJ_FALSE, &comp->stun_sess);
     if (status != PJ_SUCCESS)
-	goto on_error;
-
-    /* Associate interface with STUN session */
-    pj_stun_session_set_user_data(is->stun_sess, (void*)is);
-
-    /* Create and send STUN binding request */
-    status = pj_stun_session_create_req(is->stun_sess, 
+	return status;
+
+    /* Associate component with STUN session */
+    pj_stun_session_set_user_data(comp->stun_sess, (void*)comp);
+
+    /* Create STUN binding request */
+    status = pj_stun_session_create_req(comp->stun_sess, 
 					PJ_STUN_BINDING_REQUEST, &tdata);
     if (status != PJ_SUCCESS)
-	goto on_error;
-
-    status = pj_stun_session_send_msg(is->stun_sess, PJ_FALSE, 
+	return status;
+
+    /* Attach alias instance to tdata */
+    cand = &comp->cand_list[comp->cand_cnt];
+    tdata->user_data = (void*)cand;
+
+    /* Send STUN binding request */
+    status = pj_stun_session_send_msg(comp->stun_sess, PJ_FALSE, 
 				      &ice_st->stun_srv, 
 				      sizeof(pj_sockaddr_in), tdata);
     if (status != PJ_SUCCESS)
-	goto on_error;
-
-    /* Mark interface as pending */
-    is->status = PJ_EPENDING;
-
-    add_interface(ice_st, is, p_itf_id);
+	return status;
+
+
+    /* Add new alias to this component */
+    cand->type = PJ_ICE_CAND_TYPE_SRFLX;
+    cand->status = PJ_EPENDING;
+    cand->cand_id = -1;
+    cand->local_pref = 65535;
+    cand->foundation = calc_foundation(ice_st->pool, PJ_ICE_CAND_TYPE_SRFLX,
+				       &comp->local_addr.ipv4.sin_addr);
+
+    ++comp->cand_cnt;
+
+    /* Add pending count for this component */
+    comp->pending_cnt++;
 
     return PJ_SUCCESS;
-
-on_error:
-    destroy_ice_interface(is);
-    return status;
-}
-
-/*
- * Add TURN mapping interface.
- */
-PJ_DEF(pj_status_t) pj_ice_st_add_relay_interface(pj_ice_st *ice_st,
-						  unsigned comp_id,
-						  unsigned local_port,
-						  pj_bool_t notify,
-						  void *notify_data)
-{
-    /* Yeah, TODO */
-    PJ_UNUSED_ARG(ice_st);
-    PJ_UNUSED_ARG(comp_id);
-    PJ_UNUSED_ARG(local_port);
-    PJ_UNUSED_ARG(notify);
-    PJ_UNUSED_ARG(notify_data);
-    return -1;
-}
-
-PJ_DEF(pj_status_t) pj_ice_st_get_interfaces_status(pj_ice_st *ice_st)
+}
+
+
+/*
+ * Create the component.
+ */
+PJ_DEF(pj_status_t) pj_ice_st_create_comp(pj_ice_st *ice_st,
+					  unsigned comp_id,
+					  pj_uint32_t options,
+					  const pj_sockaddr_in *addr,
+				    	  unsigned *p_itf_id)
+{
+    pj_ice_st_comp *comp;
+    pj_status_t status;
+
+    /* Verify arguments */
+    PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL);
+
+    /* Check that component ID present */
+    PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJNATH_EICEINCOMPID);
+
+    /* Can't add new component while ICE is running */
+    PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EBUSY);
+    
+    /* Can't add new component while resolver is running */
+    PJ_ASSERT_RETURN(ice_st->has_resolver_job == PJ_FALSE, PJ_EBUSY);
+
+
+    /* Create component */
+    status = create_component(ice_st, comp_id, options, addr, &comp);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    if ((options & PJ_ICE_ST_OPT_DISABLE_STUN) == 0) {
+	status = get_stun_mapped_addr(ice_st, comp);
+	if (status != PJ_SUCCESS) {
+	    destroy_component(comp);
+	    return status;
+	}
+    }
+
+    /* Store this component */
+    if (p_itf_id)
+	*p_itf_id = ice_st->comp_cnt;
+
+    ice_st->comp[comp_id-1] = comp;
+
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pj_ice_st_get_comps_status(pj_ice_st *ice_st)
 {
     unsigned i;
     pj_status_t worst = PJ_SUCCESS;
 
-    for (i=0; i<ice_st->itf_cnt; ++i) {
-	pj_ice_st_interface *itf = ice_st->itfs[i];
-
-	if (itf->status == PJ_SUCCESS) {
+    for (i=0; i<ice_st->comp_cnt; ++i) {
+	pj_ice_st_comp *comp = ice_st->comp[i];
+
+	if (comp->last_status == PJ_SUCCESS) {
 	    /* okay */
-	} else if (itf->status == PJ_EPENDING && worst==PJ_SUCCESS) {
-	    worst = itf->status;
-	} else {
-	    worst = itf->status;
+	} else if (comp->pending_cnt && worst==PJ_SUCCESS) {
+	    worst = PJ_EPENDING;
+	    break;
+	} else if (comp->last_status != PJ_SUCCESS) {
+	    worst = comp->last_status;
+	    break;
 	}
+
+	if (worst != PJ_SUCCESS)
+	    break;
     }
 
@@ -574,6 +656,6 @@
     pj_bzero(&ice_cb, sizeof(ice_cb));
     ice_cb.on_ice_complete = &on_ice_complete;
-    ice_cb.on_rx_data = &on_rx_data;
-    ice_cb.on_tx_pkt = &on_tx_pkt;
+    ice_cb.on_rx_data = &ice_rx_data;
+    ice_cb.on_tx_pkt = &ice_tx_pkt;
 
     /* Create! */
@@ -588,13 +670,27 @@
 
     /* Add candidates */
-    for (i=0; i<ice_st->itf_cnt; ++i) {
-	pj_ice_st_interface *is= ice_st->itfs[i];
-	status = pj_ice_add_cand(ice_st->ice, is->comp_id, is->type, 
-				 is->local_pref, &is->foundation,
-				 &is->addr, &is->base_addr, NULL, 
-				 sizeof(pj_sockaddr_in), 
-				 (unsigned*)&is->cand_id);
-	if (status != PJ_SUCCESS)
-	    goto on_error;
+    for (i=0; i<ice_st->comp_cnt; ++i) {
+	unsigned j;
+	pj_ice_st_comp *comp= ice_st->comp[i];
+
+	for (j=0; j<comp->cand_cnt; ++j) {
+	    pj_ice_st_cand *cand = &comp->cand_list[j];
+
+	    /* Skip if candidate is not ready */
+	    if (cand->status != PJ_SUCCESS) {
+		PJ_LOG(5,(ice_st->obj_name, 
+			  "Candidate %d in component %d is not added",
+			  j, i));
+		continue;
+	    }
+
+	    status = pj_ice_add_cand(ice_st->ice, comp->comp_id, cand->type,
+				     cand->local_pref, &cand->foundation,
+				     &cand->addr, &comp->local_addr, NULL, 
+				     sizeof(pj_sockaddr_in), 
+				     (unsigned*)&cand->cand_id);
+	    if (status != PJ_SUCCESS)
+		goto on_error;
+	}
     }
 
@@ -602,11 +698,5 @@
 
 on_error:
-    for (i=0; i<ice_st->itf_cnt; ++i) {
-	ice_st->itfs[i]->cand_id = -1;
-    }
-    if (ice_st->ice) {
-	pj_ice_destroy(ice_st->ice);
-	ice_st->ice = NULL;
-    }
+    pj_ice_st_stop_ice(ice_st);
     return status;
 }
@@ -654,5 +744,10 @@
 	return status;
 
-    return pj_ice_start_check(ice_st->ice);
+    status = pj_ice_start_check(ice_st->ice);
+    if (status != PJ_SUCCESS) {
+	pj_ice_st_stop_ice(ice_st);
+    }
+
+    return status;
 }
 
@@ -662,4 +757,6 @@
 PJ_DECL(pj_status_t) pj_ice_st_stop_ice(pj_ice_st *ice_st)
 {
+    unsigned i;
+
     if (ice_st->ice) {
 	pj_ice_destroy(ice_st->ice);
@@ -667,19 +764,13 @@
     }
 
+    /* Invalidate all candidate Ids */
+    for (i=0; i<ice_st->comp_cnt; ++i) {
+	unsigned j;
+	for (j=0; j<ice_st->comp[i]->cand_cnt; ++j) {
+	    ice_st->comp[i]->cand_list[j].cand_id = -1;
+	}
+    }
+
     return PJ_SUCCESS;
-}
-
-/*
- * Send data to peer agent.
- */
-PJ_DEF(pj_status_t) pj_ice_st_send_data( pj_ice_st *ice_st,
-					 unsigned comp_id,
-					 const void *data,
-					 pj_size_t data_len)
-{
-    if (!ice_st->ice)
-	return PJNATH_ENOICE;
-
-    return pj_ice_send_data(ice_st->ice, comp_id, data, data_len);
 }
 
@@ -689,5 +780,4 @@
 PJ_DEF(pj_status_t) pj_ice_st_sendto( pj_ice_st *ice_st,
 				      unsigned comp_id,
-				      unsigned itf_id,
 				      const void *data,
 				      pj_size_t data_len,
@@ -696,9 +786,20 @@
 {
     pj_ssize_t pkt_size;
-    pj_ice_st_interface *is = ice_st->itfs[itf_id];
+    pj_ice_st_comp *comp;
     pj_status_t status;
 
+    PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt &&
+		     dst_addr && dst_addr_len, PJ_EINVAL);
+
+    comp = ice_st->comp[comp_id-1];
+
+    /* If ICE is available, send data with ICE */
+    if (ice_st->ice) {
+	return pj_ice_send_data(ice_st->ice, comp_id, data, data_len);
+    }
+
+    /* Otherwise send direcly with the socket */
     pkt_size = data_len;
-    status = pj_ioqueue_sendto(is->key, &is->write_op, 
+    status = pj_ioqueue_sendto(comp->key, &comp->write_op, 
 			       data, &pkt_size, 0,
 			       dst_addr, dst_addr_len);
@@ -722,30 +823,22 @@
  * Callback called by ICE session when it wants to send outgoing packet.
  */
-static pj_status_t on_tx_pkt(pj_ice *ice, 
-			     unsigned comp_id, unsigned cand_id,
-			     const void *pkt, pj_size_t size,
-			     const pj_sockaddr_t *dst_addr,
-			     unsigned dst_addr_len)
+static pj_status_t ice_tx_pkt(pj_ice *ice, 
+			      unsigned comp_id, unsigned cand_id,
+			      const void *pkt, pj_size_t size,
+			      const pj_sockaddr_t *dst_addr,
+			      unsigned dst_addr_len)
 {
     pj_ice_st *ice_st = (pj_ice_st*)ice->user_data;
-    pj_ice_st_interface *is = NULL;
-    unsigned i;
+    pj_ice_st_comp *comp = NULL;
     pj_ssize_t pkt_size;
     pj_status_t status;
 
-    PJ_UNUSED_ARG(comp_id);
-
-    for (i=0; i<ice_st->itf_cnt; ++i) {
-	if (ice_st->itfs[i]->cand_id == (int)cand_id) {
-	    is = ice_st->itfs[i];
-	    break;
-	}
-    }
-    if (is == NULL) {
-	return PJNATH_EICEINCANDID;
-    }
+    PJ_TODO(TX_TO_RELAY);
+
+    PJ_ASSERT_RETURN(comp_id && comp_id <= ice_st->comp_cnt, PJ_EINVAL);
+    comp = ice_st->comp[comp_id-1];
 
     pkt_size = size;
-    status = pj_ioqueue_sendto(is->key, &is->write_op, 
+    status = pj_ioqueue_sendto(comp->key, &comp->write_op, 
 			       pkt, &pkt_size, 0,
 			       dst_addr, dst_addr_len);
@@ -757,15 +850,15 @@
  * Callback called by ICE session when it receives application data.
  */
-static void on_rx_data(pj_ice *ice, 
-		       unsigned comp_id, unsigned cand_id,
-		       void *pkt, pj_size_t size,
-		       const pj_sockaddr_t *src_addr,
-		       unsigned src_addr_len)
+static void ice_rx_data(pj_ice *ice, 
+		        unsigned comp_id, 
+		        void *pkt, pj_size_t size,
+		        const pj_sockaddr_t *src_addr,
+		        unsigned src_addr_len)
 {
     pj_ice_st *ice_st = (pj_ice_st*)ice->user_data;
 
     if (ice_st->cb.on_rx_data) {
-	(*ice_st->cb.on_rx_data)(ice_st, comp_id, cand_id, 
-				 pkt, size, src_addr, src_addr_len);
+	(*ice_st->cb.on_rx_data)(ice_st, comp_id, pkt, size, 
+				 src_addr, src_addr_len);
     }
 }
@@ -780,11 +873,11 @@
 				    unsigned dst_addr_len)
 {
-    pj_ice_st_interface *is;
+    pj_ice_st_comp *comp;
     pj_ssize_t pkt_size;
     pj_status_t status;
 
-    is = (pj_ice_st_interface*) pj_stun_session_get_user_data(sess);
+    comp = (pj_ice_st_comp*) pj_stun_session_get_user_data(sess);
     pkt_size = size;
-    status = pj_ioqueue_sendto(is->key, &is->write_op, 
+    status = pj_ioqueue_sendto(comp->key, &comp->write_op, 
 			       pkt, &pkt_size, 0,
 			       dst_addr, dst_addr_len);
@@ -802,15 +895,21 @@
 				     const pj_stun_msg *response)
 {
-    pj_ice_st_interface *is;
+    pj_ice_st_comp *comp;
+    pj_ice_st_cand *cand = NULL;
     pj_stun_xor_mapped_addr_attr *xa;
     pj_stun_mapped_addr_attr *ma;
     pj_sockaddr *mapped_addr;
 
-    PJ_UNUSED_ARG(tdata);
-
-    is = (pj_ice_st_interface*) pj_stun_session_get_user_data(sess);
+    comp = (pj_ice_st_comp*) pj_stun_session_get_user_data(sess);
+    cand = (pj_ice_st_cand*) tdata->user_data;
+
+    /* Decrement pending count for this component */
+    pj_assert(comp->pending_cnt > 0);
+    comp->pending_cnt--;
+
     if (status != PJ_SUCCESS) {
-	is->status = status;
-	ice_st_perror(is->ice_st, "STUN Binding request failed", is->status);
+	comp->last_status = cand->status = status;
+	ice_st_perror(comp->ice_st, "STUN Binding request failed", 
+		      cand->status);
 	return;
     }
@@ -826,16 +925,20 @@
 	mapped_addr = &ma->sockaddr;
     else {
-	is->status = PJNATH_ESTUNNOMAPPEDADDR;
-	ice_st_perror(is->ice_st, "STUN Binding request failed", is->status);
+	cand->status = PJNATH_ESTUNNOMAPPEDADDR;
+	ice_st_perror(comp->ice_st, "STUN Binding request failed", 
+		      cand->status);
 	return;
     }
 
-    PJ_LOG(4,(is->ice_st->obj_name, 
+    PJ_LOG(4,(comp->ice_st->obj_name, 
 	      "STUN mapped address: %s:%d",
 	      pj_inet_ntoa(mapped_addr->ipv4.sin_addr),
 	      (int)pj_ntohs(mapped_addr->ipv4.sin_port)));
-    pj_memcpy(&is->addr, mapped_addr, sizeof(pj_sockaddr_in));
-    is->status = PJ_SUCCESS;
-
-}
-
+    pj_memcpy(&cand->addr, mapped_addr, sizeof(pj_sockaddr_in));
+    cand->status = PJ_SUCCESS;
+
+    /* Set this candidate as the default candidate */
+    comp->default_cand = (cand - comp->cand_list);
+    comp->last_status = PJ_SUCCESS;
+}
+
Index: /pjproject/trunk/pjsip-apps/build/Samples-vc.mak
===================================================================
--- /pjproject/trunk/pjsip-apps/build/Samples-vc.mak	(revision 1103)
+++ /pjproject/trunk/pjsip-apps/build/Samples-vc.mak	(revision 1104)
@@ -20,5 +20,5 @@
 
 LIBS = $(PJSUA_LIB_LIB) $(PJSIP_UA_LIB) $(PJSIP_SIMPLE_LIB) \
-	  $(PJSIP_LIB) $(PJNATH_LIB) $(PJMEDIA_CODEC_LIB) $(PJMEDIA_LIB) \
+	  $(PJSIP_LIB) $(PJMEDIA_CODEC_LIB) $(PJMEDIA_LIB) $(PJNATH_LIB) \
 	  $(PJLIB_UTIL_LIB) $(PJLIB_LIB)
 
@@ -30,5 +30,5 @@
 	  -I..\..\pjnath/include
 LDFLAGS = $(BUILD_FLAGS) $(LIBS) \
-	  ole32.lib user32.lib dsound.lib dxguid.lib netapi32.lib \
+	  Iphlpapi.lib ole32.lib user32.lib dsound.lib dxguid.lib netapi32.lib \
 	  mswsock.lib ws2_32.lib 
 
Index: /pjproject/trunk/pjsip-apps/build/pjsua.dsp
===================================================================
--- /pjproject/trunk/pjsip-apps/build/pjsua.dsp	(revision 1103)
+++ /pjproject/trunk/pjsip-apps/build/pjsua.dsp	(revision 1104)
@@ -52,5 +52,5 @@
 LINK32=link.exe
 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
-# ADD LINK32 ole32.lib user32.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib kernel32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /map:"..\bin\pjsua_vc6.map" /debug /machine:I386 /out:"../bin/pjsua_vc6.exe" /fixed:no
+# ADD LINK32 Iphlpapi.lib ole32.lib user32.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib kernel32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /map:"..\bin\pjsua_vc6.map" /debug /machine:I386 /out:"../bin/pjsua_vc6.exe" /fixed:no
 # SUBTRACT LINK32 /pdb:none
 
@@ -78,5 +78,5 @@
 LINK32=link.exe
 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 ole32.lib user32.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib kernel32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../bin/pjsua_vc6d.exe" /pdbtype:sept
+# ADD LINK32 Iphlpapi.lib ole32.lib user32.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib kernel32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../bin/pjsua_vc6d.exe" /pdbtype:sept
 
 !ENDIF 
Index: /pjproject/trunk/pjsip-apps/build/pjsua.vcproj
===================================================================
--- /pjproject/trunk/pjsip-apps/build/pjsua.vcproj	(revision 1103)
+++ /pjproject/trunk/pjsip-apps/build/pjsua.vcproj	(revision 1104)
@@ -74,5 +74,5 @@
 				Name="VCLinkerTool"
 				AdditionalOptions="/FIXED:NO"
-				AdditionalDependencies="dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib"
+				AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib"
 				OutputFile="../bin/pjsua_vc8.exe"
 				LinkIncremental="1"
@@ -169,5 +169,5 @@
 			<Tool
 				Name="VCLinkerTool"
-				AdditionalDependencies="dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib"
+				AdditionalDependencies="Iphlpapi.lib  dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib"
 				OutputFile="../bin/pjsua_vc8d.exe"
 				LinkIncremental="2"
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 1103)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 1104)
@@ -554,9 +554,13 @@
 {
     unsigned i;
+    pj_sockaddr_in addr;
     pj_status_t status;
+
+    pj_sockaddr_in_init(&addr, 0, (pj_uint16_t)cfg->port);
 
     /* Create each media transport */
     for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
-	pj_ice_st *ice_st;
+	pj_ice_st_comp comp;
+	int next_port;
 
 	status = pjmedia_ice_create(pjsua_var.med_endpt, NULL, 1,
@@ -569,45 +573,24 @@
 	}
 
-	ice_st = pjmedia_ice_get_ice_st(pjsua_var.calls[i].med_tp);
-
-	/* Add host candidates for RTP */
-	status = pj_ice_st_add_all_host_interfaces(ice_st, 1, 0);
+	status = pjmedia_ice_start_init(pjsua_var.calls[i].med_tp, 0, &addr,
+				        &pjsua_var.stun_srv.ipv4, NULL);
 	if (status != PJ_SUCCESS) {
-	    pjsua_perror(THIS_FILE, "Error adding ICE host candidates",
+	    pjsua_perror(THIS_FILE, "Error starting ICE transport",
 		         status);
 	    goto on_error;
 	}
 
-	/* Configure STUN server */
-	if (pjsua_var.stun_srv.addr.sa_family != 0) {
-	
-	    status = pj_ice_st_set_stun_addr(ice_st, 
-					     pjsua_var.media_cfg.enable_relay,
-					     &pjsua_var.stun_srv.ipv4);
-	    if (status != PJ_SUCCESS) {
-		pjsua_perror(THIS_FILE, "Error setting ICE's STUN server",
-			     status);
-		goto on_error;
-	    }
-
-	    /* Add STUN server reflexive candidate for RTP */
-	    status = pj_ice_st_add_stun_interface(ice_st, 1, 0, NULL);
-	    if (status != PJ_SUCCESS) {
-		pjsua_perror(THIS_FILE, "Error adding ICE address",
-			     status);
-		goto on_error;
-	    }
-	}
+	pjmedia_ice_get_comp(pjsua_var.calls[i].med_tp, 1, &comp);
+	next_port = pj_ntohs(comp.local_addr.ipv4.sin_port);
+	next_port += 2;
+	addr.sin_port = pj_htons((pj_uint16_t)next_port);
     }
 
     /* Wait until all ICE transports are ready */
     for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
-	pj_ice_st *ice_st;
-
-	ice_st = pjmedia_ice_get_ice_st(pjsua_var.calls[i].med_tp);
 
 	/* Wait until interface status is PJ_SUCCESS */
 	for (;;) {
-	    status = pj_ice_st_get_interfaces_status(ice_st);
+	    status = pjmedia_ice_get_init_status(pjsua_var.calls[i].med_tp);
 	    if (status == PJ_EPENDING)
 		pjsua_handle_events(100);
