ICE (work in progress): use single socket for all candidates in component, and implemented IP interface enumeration on Win32

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@1104 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjlib-util/build/pjlib_util.vcproj b/pjlib-util/build/pjlib_util.vcproj
index d744765..7ca537c 100644
--- a/pjlib-util/build/pjlib_util.vcproj
+++ b/pjlib-util/build/pjlib_util.vcproj
@@ -16,8 +16,8 @@
 	<Configurations>

 		<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"

 			UseOfMFC="0"

@@ -48,10 +48,10 @@
 				StringPooling="true"

 				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"

 				SuppressStartupBanner="true"

@@ -70,7 +70,7 @@
 			/>

 			<Tool

 				Name="VCLibrarianTool"

-				OutputFile="../lib/pjlib-util-i386-win32-vc6-release.lib"

+				OutputFile="../lib/pjlib-util-i386-win32-vc8-release.lib"

 				SuppressStartupBanner="true"

 			/>

 			<Tool

@@ -82,7 +82,7 @@
 			<Tool

 				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

 				Name="VCFxCopTool"

@@ -93,8 +93,8 @@
 		</Configuration>

 		<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"

 			UseOfMFC="0"

@@ -124,10 +124,10 @@
 				MinimalRebuild="true"

 				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"

 				SuppressStartupBanner="true"

@@ -146,7 +146,7 @@
 			/>

 			<Tool

 				Name="VCLibrarianTool"

-				OutputFile="../lib/pjlib-util-i386-win32-vc6-debug.lib"

+				OutputFile="../lib/pjlib-util-i386-win32-vc8-debug.lib"

 				SuppressStartupBanner="true"

 			/>

 			<Tool

@@ -158,7 +158,7 @@
 			<Tool

 				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

 				Name="VCFxCopTool"

diff --git a/pjlib/build/pjlib.dsp b/pjlib/build/pjlib.dsp
index 39df8bc..bd841f7 100644
--- a/pjlib/build/pjlib.dsp
+++ b/pjlib/build/pjlib.dsp
@@ -110,6 +110,11 @@
 # End Source File

 # 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

 # End Source File

@@ -254,6 +259,10 @@
 # End Source File

 # Begin Source File

 

+SOURCE=..\src\pj\ip_helper_win32.c

+# End Source File

+# Begin Source File

+

 SOURCE=..\src\pj\list.c

 # End Source File

 # Begin Source File

@@ -518,6 +527,10 @@
 # End Source File

 # Begin Source File

 

+SOURCE=..\include\pj\ip_helper.h

+# End Source File

+# Begin Source File

+

 SOURCE=..\include\pj\list.h

 # End Source File

 # Begin Source File

diff --git a/pjlib/build/pjlib.vcproj b/pjlib/build/pjlib.vcproj
index ec3c564..9218378 100644
--- a/pjlib/build/pjlib.vcproj
+++ b/pjlib/build/pjlib.vcproj
@@ -16,8 +16,8 @@
 	<Configurations>

 		<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"

 			UseOfMFC="0"

@@ -47,10 +47,10 @@
 				MinimalRebuild="true"

 				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"

 				SuppressStartupBanner="true"

@@ -69,7 +69,7 @@
 			/>

 			<Tool

 				Name="VCLibrarianTool"

-				OutputFile="../lib/pjlib-i386-win32-vc6-debug.lib"

+				OutputFile="../lib/pjlib-i386-win32-vc8-debug.lib"

 				SuppressStartupBanner="true"

 			/>

 			<Tool

@@ -81,7 +81,7 @@
 			<Tool

 				Name="VCBscMakeTool"

 				SuppressStartupBanner="true"

-				OutputFile=".\output\pjlib-i386-win32-vc6-debug/pjlib.bsc"

+				OutputFile=".\output\pjlib-i386-win32-vc8-debug/pjlib.bsc"

 			/>

 			<Tool

 				Name="VCFxCopTool"

@@ -92,8 +92,8 @@
 		</Configuration>

 		<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"

 			UseOfMFC="0"

@@ -124,10 +124,10 @@
 				StringPooling="true"

 				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"

 				SuppressStartupBanner="true"

@@ -146,7 +146,7 @@
 			/>

 			<Tool

 				Name="VCLibrarianTool"

-				OutputFile="../lib/pjlib-i386-win32-vc6-release.lib"

+				OutputFile="../lib/pjlib-i386-win32-vc8-release.lib"

 				SuppressStartupBanner="true"

 			/>

 			<Tool

@@ -158,7 +158,7 @@
 			<Tool

 				Name="VCBscMakeTool"

 				SuppressStartupBanner="true"

-				OutputFile=".\output\pjlib-i386-win32-vc6-release/pjlib.bsc"

+				OutputFile=".\output\pjlib-i386-win32-vc8-release/pjlib.bsc"

 			/>

 			<Tool

 				Name="VCFxCopTool"

@@ -538,6 +538,10 @@
 				</FileConfiguration>

 			</File>

 			<File

+				RelativePath="..\src\pj\ip_helper_win32.c"

+				>

+			</File>

+			<File

 				RelativePath="..\src\pj\list.c"

 				>

 				<FileConfiguration

@@ -1121,6 +1125,26 @@
 					</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>

+				</File>

+				<File

 					RelativePath="..\src\pj\log_writer_printk.c"

 					>

 					<FileConfiguration

@@ -1459,6 +1483,10 @@
 				>

 			</File>

 			<File

+				RelativePath="..\include\pj\ip_helper.h"

+				>

+			</File>

+			<File

 				RelativePath="..\include\pj\list.h"

 				>

 			</File>

diff --git a/pjlib/include/pj/ip_helper.h b/pjlib/include/pj/ip_helper.h
new file mode 100644
index 0000000..9515d97
--- /dev/null
+++ b/pjlib/include/pj/ip_helper.h
@@ -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__ */
+
diff --git a/pjlib/include/pj/sock.h b/pjlib/include/pj/sock.h
index d2da570..0be0258 100644
--- a/pjlib/include/pj/sock.h
+++ b/pjlib/include/pj/sock.h
@@ -207,6 +207,7 @@
     char	sin_zero[8];	/**< Padding.			    */
 };
 
+#undef s6_addr
 
 /**
  * This structure describes IPv6 address.
diff --git a/pjlib/include/pjlib.h b/pjlib/include/pjlib.h
index e300d48..025fe21 100644
--- a/pjlib/include/pjlib.h
+++ b/pjlib/include/pjlib.h
@@ -37,6 +37,7 @@
 #include <pj/guid.h>
 #include <pj/hash.h>
 #include <pj/ioqueue.h>
+#include <pj/ip_helper.h>
 #include <pj/list.h>
 #include <pj/lock.h>
 #include <pj/log.h>
diff --git a/pjlib/src/pj/ip_helper_generic.c b/pjlib/src/pj/ip_helper_generic.c
new file mode 100644
index 0000000..3b713f5
--- /dev/null
+++ b/pjlib/src/pj/ip_helper_generic.c
@@ -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;
+}
+
diff --git a/pjlib/src/pj/ip_helper_win32.c b/pjlib/src/pj/ip_helper_win32.c
new file mode 100644
index 0000000..094cfc9
--- /dev/null
+++ b/pjlib/src/pj/ip_helper_win32.c
@@ -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;
+}
+
+
+
diff --git a/pjmedia/include/pjmedia/transport_ice.h b/pjmedia/include/pjmedia/transport_ice.h
index e676730..0fcd5a4 100644
--- a/pjmedia/include/pjmedia/transport_ice.h
+++ b/pjmedia/include/pjmedia/transport_ice.h
@@ -46,8 +46,16 @@
 					pjmedia_transport **p_tp);
 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,
 					  pj_ice_role role,
diff --git a/pjmedia/src/pjmedia/transport_ice.c b/pjmedia/src/pjmedia/transport_ice.c
index 02aec2e..445f373 100644
--- a/pjmedia/src/pjmedia/transport_ice.c
+++ b/pjmedia/src/pjmedia/transport_ice.c
@@ -69,8 +69,7 @@
 /*
  * 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,
 			   unsigned src_addr_len);
@@ -99,7 +98,6 @@
     pj_ice_st *ice_st;
     pj_ice_st_cb ice_st_cb;
     struct transport_ice *tp_ice;
-    unsigned i;
     pj_status_t status;
 
     PJ_UNUSED_ARG(endpt);
@@ -110,16 +108,11 @@
     ice_st_cb.on_rx_data = &ice_on_rx_data;
 
     /* 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 */
     tp_ice = PJ_POOL_ZALLOC_T(ice_st->pool, struct transport_ice);
@@ -135,10 +128,6 @@
 	*p_tp = &tp_ice->base;
 
     return PJ_SUCCESS;
-
-on_error:
-    pj_ice_st_destroy(ice_st);
-    return status;
 }
 
 
@@ -157,7 +146,65 @@
 }
 
 
-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;
     return tp_ice->ice_st;
@@ -415,34 +462,30 @@
 			       pjmedia_sock_info *info)
 {
     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];
+    /* 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));
 
-	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;
+    /* 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));
     }
 
-    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,
-	      sizeof(pj_sockaddr_in));
 
     return PJ_SUCCESS;
 }
@@ -491,13 +534,9 @@
 			       pj_size_t size)
 {
     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));
 }
 
 
@@ -505,21 +544,18 @@
 			        const void *pkt,
 			        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
+    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, 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,
 			   unsigned src_addr_len)
@@ -531,9 +567,10 @@
     else if (comp_id==2 && tp_ice->rtcp_cb)
 	(*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);
 }
 
 
diff --git a/pjnath/include/pjnath/ice.h b/pjnath/include/pjnath/ice.h
index 10faa21..cd3a4e7 100644
--- a/pjnath/include/pjnath/ice.h
+++ b/pjnath/include/pjnath/ice.h
@@ -150,7 +150,6 @@
 			     const pj_sockaddr_t *dst_addr,
 			     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,
 			      unsigned src_addr_len);
diff --git a/pjnath/include/pjnath/ice_stream_transport.h b/pjnath/include/pjnath/ice_stream_transport.h
index 5920732..fbdd9b4 100644
--- a/pjnath/include/pjnath/ice_stream_transport.h
+++ b/pjnath/include/pjnath/ice_stream_transport.h
@@ -44,7 +44,7 @@
 typedef struct pj_ice_st_cb
 {
     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,
 			  unsigned src_addr_len);
@@ -54,32 +54,55 @@
 } pj_ice_st_cb;
 
 
+#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
 {
-    unsigned		 comp_id;
-} pj_ice_st_comp;
-
-
-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_uint32_t		 options;
     pj_sock_t		 sock;
-    pj_sockaddr		 addr;
-    pj_sockaddr		 base_addr;
+
+    pj_stun_session	*stun_sess;
+
+    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];
     pj_ioqueue_op_key_t	 read_op;
     pj_ioqueue_op_key_t	 write_op;
     pj_sockaddr		 src_addr;
     int			 src_addr_len;
-    pj_stun_session	*stun_sess;
-} pj_ice_st_interface;
+
+} pj_ice_st_comp;
 
 
 struct pj_ice_st
@@ -93,54 +116,37 @@
     pj_ice		    *ice;
 
     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;
 };
 
 
 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,
 				      pj_ice_st **p_ice_st);
 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,
 					pj_ice_role role,
@@ -156,13 +162,8 @@
 					 const pj_ice_cand rem_cand[]);
 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,
 				      const pj_sockaddr_t *dst_addr,
diff --git a/pjnath/src/pjnath/ice.c b/pjnath/src/pjnath/ice.c
index 50f911f..bfae8da 100644
--- a/pjnath/src/pjnath/ice.c
+++ b/pjnath/src/pjnath/ice.c
@@ -1709,7 +1709,7 @@
 					   PJ_STUN_IS_DATAGRAM,
 					   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);
     }
     
diff --git a/pjnath/src/pjnath/ice_stream_transport.c b/pjnath/src/pjnath/ice_stream_transport.c
index c479a3d..86dcab3 100644
--- a/pjnath/src/pjnath/ice_stream_transport.c
+++ b/pjnath/src/pjnath/ice_stream_transport.c
@@ -20,6 +20,7 @@
 #include <pjnath/errno.h>
 #include <pj/addr_resolv.h>
 #include <pj/assert.h>
+#include <pj/ip_helper.h>
 #include <pj/log.h>
 #include <pj/pool.h>
 #include <pj/string.h>
@@ -28,13 +29,13 @@
 
 /* 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,
 			      unsigned src_addr_len);
@@ -44,7 +45,7 @@
                              pj_ioqueue_op_key_t *op_key, 
                              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);
 
 /* STUN session callback */
@@ -85,167 +86,11 @@
 
 
 /* 
- * 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,
 				      pj_ice_st **p_ice_st)
@@ -253,7 +98,7 @@
     pj_pool_t *pool;
     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);
 
     if (name == NULL)
@@ -265,15 +110,21 @@
     pj_memcpy(ice_st->obj_name, pool->obj_name, PJ_MAX_OBJ_NAME);
     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"));
 
     *p_ice_st = ice_st;
     return PJ_SUCCESS;
 }
 
+/* Destroy ICE */
 static void destroy_ice_st(pj_ice_st *ice_st, pj_status_t reason)
 {
     unsigned i;
@@ -290,12 +141,14 @@
 	ice_st->ice = NULL;
     }
 
-    /* Destroy all interfaces */
-    for (i=0; i<ice_st->itf_cnt; ++i) {
-	destroy_ice_interface(ice_st->itfs[i]);
-	ice_st->itfs[i] = NULL;
+    /* 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->itf_cnt = 0;
+    ice_st->comp_cnt = 0;
 
     /* Done */
     pj_pool_release(ice_st->pool);
@@ -317,15 +170,13 @@
 /*
  * 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;
 }
@@ -333,74 +184,394 @@
 /*
  * 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_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);
 
-    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));
+    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)
+
+/* Calculate foundation */
+static pj_str_t calc_foundation(pj_pool_t *pool,
+				pj_ice_cand_type type,
+				const pj_in_addr *base_addr)
 {
-    /* Verify arguments */
-    PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL);
+    char foundation[32];
+    pj_str_t result;
 
-    /* Can only add component when we don't have active ICE session */
-    PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EBUSY);
+    pj_ansi_snprintf(foundation, sizeof(foundation), "%c%x", 
+		     get_type_prefix(type),
+		     (int)pj_ntohl(base_addr->s_addr));
+    pj_strdup2(pool, &result, foundation);
 
-    /* Check that we don't have too many components */
-    PJ_ASSERT_RETURN(ice_st->comp_cnt < PJ_ICE_MAX_COMP, PJ_ETOOMANY);
+    return result;
+}
 
-    /* Component ID must be valid */
-    PJ_ASSERT_RETURN(comp_id <= PJ_ICE_MAX_COMP, PJNATH_EICEINCOMPID);
+/*  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;
 
-    /* First component ID must be 1, second must be 2, etc., and 
-     * they must be registered in order.
+    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;
+
+    /* 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)
      */
-    PJ_ASSERT_RETURN(ice_st->comps[comp_id-1] == ice_st->comp_cnt, 
-		     PJNATH_EICEINCOMPID);
+    addr_len = sizeof(comp->local_addr);
+    status = pj_sock_getsockname(comp->sock, &comp->local_addr, &addr_len);
+    if (status != PJ_SUCCESS)
+	goto on_error;
 
-    /* All in order, add the component. */
-    ice_st->comps[ice_st->comp_cnt++] = comp_id;
+    /* 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;
+
+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;
+
+    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, PJ_EINVAL);
+    
+    /* 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, &comp->stun_sess);
+    if (status != PJ_SUCCESS)
+	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)
+	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)
+	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;
 }
 
-/* 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.
+ * Create the component.
  */
-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_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_interface *is;
+    pj_ice_st_comp *comp;
     pj_status_t status;
 
     /* Verify arguments */
@@ -409,145 +580,56 @@
     /* 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 */
+    /* 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 interface */
-    status = create_ice_interface(ice_st, PJ_ICE_CAND_TYPE_HOST, comp_id,
-				  local_pref, addr, &is);
+
+    /* Create component */
+    status = create_component(ice_st, comp_id, options, addr, &comp);
     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));
+    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 interface */
-    add_interface(ice_st, is, p_itf_id);
+    /* Store this component */
+    if (p_itf_id)
+	*p_itf_id = ice_st->comp_cnt;
 
-    /* Set interface status to SUCCESS */
-    is->status = PJ_SUCCESS;
+    ice_st->comp[comp_id-1] = 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;
-    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;
-    pj_stun_session_cb sess_cb;
-    pj_stun_tx_data *tdata;
-    pj_status_t status;
-
-    PJ_ASSERT_RETURN(ice_st && comp_id, 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 */
-    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);
-    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, 
-					PJ_STUN_BINDING_REQUEST, &tdata);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-    status = pj_stun_session_send_msg(is->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 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)
+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];
+    for (i=0; i<ice_st->comp_cnt; ++i) {
+	pj_ice_st_comp *comp = ice_st->comp[i];
 
-	if (itf->status == PJ_SUCCESS) {
+	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;
     }
 
     return worst;
@@ -573,8 +655,8 @@
     /* Init callback */
     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! */
     status = pj_ice_create(&ice_st->stun_cfg, ice_st->obj_name, role, 
@@ -587,27 +669,35 @@
     ice_st->ice->user_data = (void*)ice_st;
 
     /* 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;
+	}
     }
 
     return PJ_SUCCESS;
 
 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;
 }
 
@@ -653,7 +743,12 @@
     if (status != PJ_SUCCESS)
 	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;
 }
 
 /*
@@ -661,45 +756,51 @@
  */
 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);
 	ice_st->ice = NULL;
     }
 
+    /* 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);
-}
-
-/*
  * Send packet using non-ICE means (e.g. when ICE was not negotiated).
  */
 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,
 				      const pj_sockaddr_t *dst_addr,
 				      int dst_addr_len)
 {
     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);
     
@@ -721,32 +822,24 @@
 /*
  * 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);
+    PJ_TODO(TX_TO_RELAY);
 
-    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_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);
     
@@ -756,17 +849,17 @@
 /*
  * 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);
     }
 }
 
@@ -779,13 +872,13 @@
 				    const pj_sockaddr_t *dst_addr,
 				    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);
     
@@ -801,17 +894,23 @@
 				     pj_stun_tx_data *tdata,
 				     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);
+    comp = (pj_ice_st_comp*) pj_stun_session_get_user_data(sess);
+    cand = (pj_ice_st_cand*) tdata->user_data;
 
-    is = (pj_ice_st_interface*) pj_stun_session_get_user_data(sess);
+    /* 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;
     }
 
@@ -825,17 +924,21 @@
     else if (ma)
 	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;
 }
 
diff --git a/pjsip-apps/build/Samples-vc.mak b/pjsip-apps/build/Samples-vc.mak
index 11af4f3..1b83018 100644
--- a/pjsip-apps/build/Samples-vc.mak
+++ b/pjsip-apps/build/Samples-vc.mak
@@ -19,7 +19,7 @@
 PJSUA_LIB_LIB = ..\..\pjsip\lib\pjsua-lib-$(TARGET)$(LIBEXT)
 
 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)
 
 CFLAGS 	= /DPJ_WIN32=1 /DPJ_M_I386=1 \
@@ -29,7 +29,7 @@
 	  -I..\..\pjmedia\include \
 	  -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 
 
 SRCDIR = ..\src\samples
diff --git a/pjsip-apps/build/pjsua.dsp b/pjsip-apps/build/pjsua.dsp
index 5ab3d3d..7aafa8d 100644
--- a/pjsip-apps/build/pjsua.dsp
+++ b/pjsip-apps/build/pjsua.dsp
@@ -51,7 +51,7 @@
 # ADD BSC32 /nologo

 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

 

 !ELSEIF  "$(CFG)" == "pjsua - Win32 Debug"

@@ -77,7 +77,7 @@
 # ADD BSC32 /nologo

 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 

 

diff --git a/pjsip-apps/build/pjsua.vcproj b/pjsip-apps/build/pjsua.vcproj
index cf578a9..ae59822 100644
--- a/pjsip-apps/build/pjsua.vcproj
+++ b/pjsip-apps/build/pjsua.vcproj
@@ -73,7 +73,7 @@
 			<Tool

 				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"

 				SuppressStartupBanner="true"

@@ -168,7 +168,7 @@
 			/>

 			<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"

 				SuppressStartupBanner="true"

diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c
index b8b0f33..2e3b88a 100644
--- a/pjsip/src/pjsua-lib/pjsua_media.c
+++ b/pjsip/src/pjsua-lib/pjsua_media.c
@@ -553,11 +553,15 @@
 static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg)
 {
     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,
 				    &pjsua_var.stun_cfg, 
@@ -568,47 +572,26 @@
 	    goto on_error;
 	}
 
-	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);
 	    else