Index: pjproject/trunk/pjlib-util/build/pjlib_util.vcproj
===================================================================
--- pjproject/trunk/pjlib-util/build/pjlib_util.vcproj	(revision 1866)
+++ pjproject/trunk/pjlib-util/build/pjlib_util.vcproj	(revision 1867)
@@ -4,5 +4,5 @@
 	Version="8.00"
 	Name="pjlib_util"
-	ProjectGUID="{FE07F272-AE7F-4549-9E9F-EF9B80CB1693}"
+	ProjectGUID="{E79CE31A-3681-4F0C-8BE1-C43C0702EFFB}"
 	RootNamespace="pjlib_util"
 	>
Index: pjproject/trunk/pjlib/build/pjlib.vcproj
===================================================================
--- pjproject/trunk/pjlib/build/pjlib.vcproj	(revision 1866)
+++ pjproject/trunk/pjlib/build/pjlib.vcproj	(revision 1867)
@@ -4,5 +4,5 @@
 	Version="8.00"
 	Name="pjlib"
-	ProjectGUID="{DA0E03ED-53A7-4050-8A85-90541C5509F8}"
+	ProjectGUID="{DE592F40-CEF0-4B82-8EFB-A92D0C88A1EF}"
 	RootNamespace="pjlib"
 	>
Index: pjproject/trunk/pjnath/build/pjnath.dsw
===================================================================
--- pjproject/trunk/pjnath/build/pjnath.dsw	(revision 1866)
+++ pjproject/trunk/pjnath/build/pjnath.dsw	(revision 1867)
@@ -61,5 +61,5 @@
 ###############################################################################
 
-Project: "pjstun_client"=.\pjstun_client.dsp - Package Owner=<4>
+Project: "pjstun_srv_test"=.\pjstun_srv_test.dsp - Package Owner=<4>
 
 Package=<5>
@@ -82,5 +82,5 @@
 ###############################################################################
 
-Project: "pjstun_srv_test"=.\pjstun_srv_test.dsp - Package Owner=<4>
+Project: "pjturn_client"=.\pjturn_client.dsp - Package Owner=<4>
 
 Package=<5>
Index: pjproject/trunk/pjnath/build/pjnath.vcproj
===================================================================
--- pjproject/trunk/pjnath/build/pjnath.vcproj	(revision 1866)
+++ pjproject/trunk/pjnath/build/pjnath.vcproj	(revision 1867)
@@ -320,4 +320,12 @@
 				</FileConfiguration>
 			</File>
+			<File
+				RelativePath="..\src\pjnath\turn_session.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\pjnath\turn_udp.c"
+				>
+			</File>
 		</Filter>
 		<Filter
@@ -374,5 +382,9 @@
 			</File>
 			<File
-				RelativePath="..\include\pjnath\turn_client.h"
+				RelativePath="..\include\pjnath\turn_session.h"
+				>
+			</File>
+			<File
+				RelativePath="..\include\pjnath\turn_udp.h"
 				>
 			</File>
Index: pjproject/trunk/pjnath/build/pjstun_client.dsp
===================================================================
--- pjproject/trunk/pjnath/build/pjstun_client.dsp	(revision 1866)
+++ 	(revision )
@@ -1,102 +1,0 @@
-# Microsoft Developer Studio Project File - Name="pjstun_client" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Console Application" 0x0103
-
-CFG=pjstun_client - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE 
-!MESSAGE NMAKE /f "pjstun_client.mak".
-!MESSAGE 
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE 
-!MESSAGE NMAKE /f "pjstun_client.mak" CFG="pjstun_client - Win32 Debug"
-!MESSAGE 
-!MESSAGE Possible choices for configuration are:
-!MESSAGE 
-!MESSAGE "pjstun_client - Win32 Release" (based on "Win32 (x86) Console Application")
-!MESSAGE "pjstun_client - Win32 Debug" (based on "Win32 (x86) Console Application")
-!MESSAGE 
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF  "$(CFG)" == "pjstun_client - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "./output/pjstun-client-i386-win32-vc6-release"
-# PROP BASE Intermediate_Dir "./output/pjstun-client-i386-win32-vc6-release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "./output/pjstun-client-i386-win32-vc6-release"
-# PROP Intermediate_Dir "./output/pjstun-client-i386-win32-vc6-release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /MD /W3 /GX /O2 /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /c
-# ADD BASE RSC /l 0x409 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
-# ADD LINK32 netapi32.lib mswsock.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"../bin/pjstun-client-i386-win32-vc6-release.exe"
-
-!ELSEIF  "$(CFG)" == "pjstun_client - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "./output/pjstun-client-i386-win32-vc6-debug"
-# PROP BASE Intermediate_Dir "./output/pjstun-client-i386-win32-vc6-debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "./output/pjstun-client-i386-win32-vc6-debug"
-# PROP Intermediate_Dir "./output/pjstun-client-i386-win32-vc6-debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /GZ /c
-# ADD BASE RSC /l 0x409 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 netapi32.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../bin/pjstun-client-i386-win32-vc6-debug.exe" /pdbtype:sept
-
-!ENDIF 
-
-# Begin Target
-
-# Name "pjstun_client - Win32 Release"
-# Name "pjstun_client - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE="..\src\pjstun-client\client_main.c"
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# End Group
-# Begin Group "Resource Files"
-
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
-# End Group
-# End Target
-# End Project
Index: pjproject/trunk/pjnath/build/pjstun_client.vcproj
===================================================================
--- pjproject/trunk/pjnath/build/pjstun_client.vcproj	(revision 1866)
+++ 	(revision )
@@ -1,246 +1,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
-	ProjectType="Visual C++"
-	Version="8.00"
-	Name="pjstun_client"
-	ProjectGUID="{D13A6424-23A4-4990-998D-F80C63704580}"
-	RootNamespace="pjstun_client"
-	>
-	<Platforms>
-		<Platform
-			Name="Win32"
-		/>
-	</Platforms>
-	<ToolFiles>
-	</ToolFiles>
-	<Configurations>
-		<Configuration
-			Name="Release|Win32"
-			OutputDirectory="./output/pjstun-client-i386-win32-vc8-release"
-			IntermediateDirectory="./output/pjstun-client-i386-win32-vc8-release"
-			ConfigurationType="1"
-			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
-			UseOfMFC="0"
-			ATLMinimizesCRunTimeLibraryUsage="false"
-			CharacterSet="2"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-				TypeLibraryName="./output/pjstun-client-i386-win32-vc8-release/pjstun_client.tlb"
-				HeaderFileName=""
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				Optimization="2"
-				InlineFunctionExpansion="1"
-				AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include"
-				PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;PJ_WIN32=1;PJ_M_I386=1"
-				StringPooling="true"
-				RuntimeLibrary="2"
-				EnableFunctionLevelLinking="true"
-				PrecompiledHeaderFile="./output/pjstun-client-i386-win32-vc8-release/pjstun_client.pch"
-				AssemblerListingLocation="./output/pjstun-client-i386-win32-vc8-release/"
-				ObjectFile="./output/pjstun-client-i386-win32-vc8-release/"
-				ProgramDataBaseFileName="./output/pjstun-client-i386-win32-vc8-release/"
-				BrowseInformation="1"
-				WarningLevel="3"
-				SuppressStartupBanner="true"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-				PreprocessorDefinitions="NDEBUG"
-				Culture="1033"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				AdditionalDependencies="netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib "
-				OutputFile="../bin/pjstun-client-i386-win32-vc8-release.exe"
-				LinkIncremental="1"
-				SuppressStartupBanner="true"
-				ProgramDatabaseFile="./output/pjstun-client-i386-win32-vc8-release/pjstun-client-i386-win32-vc8-release.pdb"
-				SubSystem="1"
-				TargetMachine="1"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-				SuppressStartupBanner="true"
-				OutputFile="./output/pjstun-client-i386-win32-vc8-release/pjstun_client.bsc"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCWebDeploymentTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-		<Configuration
-			Name="Debug|Win32"
-			OutputDirectory="./output/pjstun-client-i386-win32-vc8-debug"
-			IntermediateDirectory="./output/pjstun-client-i386-win32-vc8-debug"
-			ConfigurationType="1"
-			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
-			UseOfMFC="0"
-			ATLMinimizesCRunTimeLibraryUsage="false"
-			CharacterSet="2"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-				TypeLibraryName="./output/pjstun-client-i386-win32-vc8-debug/pjstun_client.tlb"
-				HeaderFileName=""
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				Optimization="0"
-				AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include"
-				PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;PJ_WIN32=1;PJ_M_I386=1"
-				MinimalRebuild="true"
-				BasicRuntimeChecks="3"
-				RuntimeLibrary="1"
-				PrecompiledHeaderFile="./output/pjstun-client-i386-win32-vc8-debug/pjstun_client.pch"
-				AssemblerListingLocation="./output/pjstun-client-i386-win32-vc8-debug/"
-				ObjectFile="./output/pjstun-client-i386-win32-vc8-debug/"
-				ProgramDataBaseFileName="./output/pjstun-client-i386-win32-vc8-debug/"
-				BrowseInformation="1"
-				WarningLevel="3"
-				SuppressStartupBanner="true"
-				DebugInformationFormat="4"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-				PreprocessorDefinitions="_DEBUG"
-				Culture="1033"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				AdditionalDependencies="netapi32.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib "
-				OutputFile="../bin/pjstun-client-i386-win32-vc8-debug.exe"
-				LinkIncremental="2"
-				SuppressStartupBanner="true"
-				GenerateDebugInformation="true"
-				ProgramDatabaseFile="./output/pjstun-client-i386-win32-vc8-debug/pjstun-client-i386-win32-vc8-debug.pdb"
-				SubSystem="1"
-				TargetMachine="1"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-				SuppressStartupBanner="true"
-				OutputFile="./output/pjstun-client-i386-win32-vc8-debug/pjstun_client.bsc"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCWebDeploymentTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<Filter
-			Name="Source Files"
-			Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-			>
-			<File
-				RelativePath="..\src\pjstun-client\client_main.c"
-				>
-				<FileConfiguration
-					Name="Release|Win32"
-					>
-					<Tool
-						Name="VCCLCompilerTool"
-						AdditionalIncludeDirectories=""
-						PreprocessorDefinitions=""
-					/>
-				</FileConfiguration>
-				<FileConfiguration
-					Name="Debug|Win32"
-					>
-					<Tool
-						Name="VCCLCompilerTool"
-						AdditionalIncludeDirectories=""
-						PreprocessorDefinitions=""
-					/>
-				</FileConfiguration>
-			</File>
-		</Filter>
-		<Filter
-			Name="Header Files"
-			Filter="h;hpp;hxx;hm;inl"
-			>
-		</Filter>
-		<Filter
-			Name="Resource Files"
-			Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
-			>
-		</Filter>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>
Index: pjproject/trunk/pjnath/build/pjturn_client.dsp
===================================================================
--- pjproject/trunk/pjnath/build/pjturn_client.dsp	(revision 1867)
+++ pjproject/trunk/pjnath/build/pjturn_client.dsp	(revision 1867)
@@ -0,0 +1,102 @@
+# Microsoft Developer Studio Project File - Name="pjturn_client" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=pjturn_client - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "pjturn_client.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "pjturn_client.mak" CFG="pjturn_client - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "pjturn_client - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "pjturn_client - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "pjturn_client - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "./output/pjturn-client-i386-win32-vc6-release"
+# PROP BASE Intermediate_Dir "./output/pjturn-client-i386-win32-vc6-release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "./output/pjturn-client-i386-win32-vc6-release"
+# PROP Intermediate_Dir "./output/pjturn-client-i386-win32-vc6-release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 netapi32.lib mswsock.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"../bin/pjturn-client-i386-win32-vc6-release.exe"
+
+!ELSEIF  "$(CFG)" == "pjturn_client - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "./output/pjturn-client-i386-win32-vc6-debug"
+# PROP BASE Intermediate_Dir "./output/pjturn-client-i386-win32-vc6-debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "./output/pjturn-client-i386-win32-vc6-debug"
+# PROP Intermediate_Dir "./output/pjturn-client-i386-win32-vc6-debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 netapi32.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../bin/pjturn-client-i386-win32-vc6-debug.exe" /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "pjturn_client - Win32 Release"
+# Name "pjturn_client - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\src\pjturn-client\client_main.c"
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
Index: pjproject/trunk/pjnath/build/pjturn_client.vcproj
===================================================================
--- pjproject/trunk/pjnath/build/pjturn_client.vcproj	(revision 1867)
+++ pjproject/trunk/pjnath/build/pjturn_client.vcproj	(revision 1867)
@@ -0,0 +1,246 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="pjturn_client"
+	ProjectGUID="{D13A6424-23A4-4990-998D-F80C63704580}"
+	RootNamespace="pjturn_client"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="./output/pjturn-client-i386-win32-vc8-release"
+			IntermediateDirectory="./output/pjturn-client-i386-win32-vc8-release"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="false"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TypeLibraryName="./output/pjturn-client-i386-win32-vc8-release/pjturn_client.tlb"
+				HeaderFileName=""
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				InlineFunctionExpansion="1"
+				AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include"
+				PreprocessorDefinitions="NDEBUG;WIN32;_CONSOLE;PJ_WIN32=1;PJ_M_I386=1"
+				StringPooling="true"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				PrecompiledHeaderFile="./output/pjturn-client-i386-win32-vc8-release/pjturn_client.pch"
+				AssemblerListingLocation="./output/pjturn-client-i386-win32-vc8-release/"
+				ObjectFile="./output/pjturn-client-i386-win32-vc8-release/"
+				ProgramDataBaseFileName="./output/pjturn-client-i386-win32-vc8-release/"
+				BrowseInformation="1"
+				WarningLevel="3"
+				SuppressStartupBanner="true"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				PreprocessorDefinitions="NDEBUG"
+				Culture="1033"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib "
+				OutputFile="../bin/pjturn-client-i386-win32-vc8-release.exe"
+				LinkIncremental="1"
+				SuppressStartupBanner="true"
+				ProgramDatabaseFile="./output/pjturn-client-i386-win32-vc8-release/pjturn-client-i386-win32-vc8-release.pdb"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+				SuppressStartupBanner="true"
+				OutputFile="./output/pjturn-client-i386-win32-vc8-release/pjturn_client.bsc"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="./output/pjturn-client-i386-win32-vc8-debug"
+			IntermediateDirectory="./output/pjturn-client-i386-win32-vc8-debug"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="false"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TypeLibraryName="./output/pjturn-client-i386-win32-vc8-debug/pjturn_client.tlb"
+				HeaderFileName=""
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include"
+				PreprocessorDefinitions="_DEBUG;WIN32;_CONSOLE;PJ_WIN32=1;PJ_M_I386=1"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				PrecompiledHeaderFile="./output/pjturn-client-i386-win32-vc8-debug/pjturn_client.pch"
+				AssemblerListingLocation="./output/pjturn-client-i386-win32-vc8-debug/"
+				ObjectFile="./output/pjturn-client-i386-win32-vc8-debug/"
+				ProgramDataBaseFileName="./output/pjturn-client-i386-win32-vc8-debug/"
+				BrowseInformation="1"
+				WarningLevel="3"
+				SuppressStartupBanner="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				PreprocessorDefinitions="_DEBUG"
+				Culture="1033"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="netapi32.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib "
+				OutputFile="../bin/pjturn-client-i386-win32-vc8-debug.exe"
+				LinkIncremental="2"
+				SuppressStartupBanner="true"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="./output/pjturn-client-i386-win32-vc8-debug/pjturn-client-i386-win32-vc8-debug.pdb"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+				SuppressStartupBanner="true"
+				OutputFile="./output/pjturn-client-i386-win32-vc8-debug/pjturn_client.bsc"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+			>
+			<File
+				RelativePath="..\src\pjturn-client\client_main.c"
+				>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						AdditionalIncludeDirectories=""
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						AdditionalIncludeDirectories=""
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
Index: pjproject/trunk/pjnath/include/pjnath.h
===================================================================
--- pjproject/trunk/pjnath/include/pjnath.h	(revision 1866)
+++ pjproject/trunk/pjnath/include/pjnath.h	(revision 1867)
@@ -29,4 +29,5 @@
 #include <pjnath/stun_transaction.h>
 #include <pjnath/turn_session.h>
+#include <pjnath/turn_udp.h>
 #include <pjnath/types.h>
 
Index: pjproject/trunk/pjnath/include/pjnath/turn_session.h
===================================================================
--- pjproject/trunk/pjnath/include/pjnath/turn_session.h	(revision 1866)
+++ pjproject/trunk/pjnath/include/pjnath/turn_session.h	(revision 1867)
@@ -193,4 +193,14 @@
 {
     /**
+     * Session state.
+     */
+    pj_turn_state_t state;
+
+    /**
+     * Type of connection to the TURN server.
+     */
+    pj_turn_tp_type tp_type;
+
+    /**
      * The relay address
      */
@@ -198,7 +208,12 @@
 
     /**
-     * The TURN server address for informational purpose.
+     * The selected TURN server address.
      */
     pj_sockaddr	    server;
+
+    /**
+     * Current seconds before allocation expires.
+     */
+    int		    lifetime;
 
 } pj_turn_session_info;
@@ -231,4 +246,10 @@
 
 /**
+ * Get TURN session info.
+ */
+PJ_DECL(pj_status_t) pj_turn_session_get_info(pj_turn_session *sess,
+					      pj_turn_session_info *info);
+
+/**
  * Re-assign user data.
  */
Index: pjproject/trunk/pjnath/include/pjnath/turn_udp.h
===================================================================
--- pjproject/trunk/pjnath/include/pjnath/turn_udp.h	(revision 1866)
+++ pjproject/trunk/pjnath/include/pjnath/turn_udp.h	(revision 1867)
@@ -96,4 +96,11 @@
 PJ_DECL(void*) pj_turn_udp_get_user_data(pj_turn_udp *udp_rel);
 
+
+/**
+ * Get info.
+ */
+PJ_DECL(pj_status_t) pj_turn_udp_get_info(pj_turn_udp *udp_rel,
+					  pj_turn_session_info *info);
+
 /**
  * Initialize.
Index: pjproject/trunk/pjnath/src/pjnath/turn_session.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/turn_session.c	(revision 1866)
+++ pjproject/trunk/pjnath/src/pjnath/turn_session.c	(revision 1867)
@@ -95,4 +95,6 @@
     pj_bool_t		 pending_alloc;
     pj_turn_alloc_param	 alloc_param;
+
+    pj_sockaddr		 relay_addr;
 
     pj_hash_table_t	*peer_table;
@@ -369,4 +371,31 @@
 
 /*
+ * Get TURN session info.
+ */
+PJ_DEF(pj_status_t) pj_turn_session_get_info( pj_turn_session *sess,
+					      pj_turn_session_info *info)
+{
+    pj_time_val now;
+
+    PJ_ASSERT_RETURN(sess && info, PJ_EINVAL);
+
+    pj_gettimeofday(&now);
+
+    info->state = sess->state;
+    info->tp_type = sess->tp_type;
+    info->lifetime = sess->expiry.sec - now.sec;
+
+    if (sess->srv_addr)
+	pj_memcpy(&info->server, sess->srv_addr, sizeof(info->server));
+    else
+	pj_bzero(&info->server, sizeof(info->server));
+
+    pj_memcpy(&info->relay_addr, &sess->relay_addr, sizeof(sess->relay_addr));
+
+    return PJ_SUCCESS;
+}
+
+
+/*
  * Re-assign user data.
  */
@@ -991,4 +1020,6 @@
     }
     
+    /* Save relayed address */
+    pj_memcpy(&sess->relay_addr, &raddr_attr->sockaddr, sizeof(pj_sockaddr));
 
     /* Success */
Index: pjproject/trunk/pjnath/src/pjnath/turn_udp.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/turn_udp.c	(revision 1866)
+++ pjproject/trunk/pjnath/src/pjnath/turn_udp.c	(revision 1867)
@@ -167,4 +167,21 @@
 }
 
+/**
+ * Get info.
+ */
+PJ_DEF(pj_status_t) pj_turn_udp_get_info(pj_turn_udp *udp_rel,
+					 pj_turn_session_info *info)
+{
+    PJ_ASSERT_RETURN(udp_rel && info, PJ_EINVAL);
+
+    if (udp_rel->sess) {
+	return pj_turn_session_get_info(udp_rel->sess, info);
+    } else {
+	pj_bzero(info, sizeof(*info));
+	info->state = PJ_TURN_STATE_NULL;
+	return PJ_SUCCESS;
+    }
+}
+
 /*
  * Initialize.
@@ -179,4 +196,7 @@
     pj_status_t status;
 
+    PJ_ASSERT_RETURN(udp_rel && domain, PJ_EINVAL);
+    PJ_ASSERT_RETURN(udp_rel->sess, PJ_EINVALIDOP);
+
     status = pj_turn_session_set_server(udp_rel->sess, domain, default_port,
 					resolver);
@@ -184,7 +204,9 @@
 	return status;
 
-    status = pj_turn_session_set_cred(udp_rel->sess, cred);
-    if (status != PJ_SUCCESS)
-	return status;
+    if (cred) {
+	status = pj_turn_session_set_cred(udp_rel->sess, cred);
+	if (status != PJ_SUCCESS)
+	    return status;
+    }
 
     status = pj_turn_session_alloc(udp_rel->sess, param);
@@ -204,4 +226,9 @@
 					unsigned addr_len)
 {
+    PJ_ASSERT_RETURN(udp_rel && addr && addr_len, PJ_EINVAL);
+
+    if (udp_rel->sess == NULL)
+	return PJ_EINVALIDOP;
+
     return pj_turn_session_sendto(udp_rel->sess, pkt, pkt_len, 
 				  addr, addr_len);
@@ -215,4 +242,7 @@
 					      unsigned addr_len)
 {
+    PJ_ASSERT_RETURN(udp_rel && peer && addr_len, PJ_EINVAL);
+    PJ_ASSERT_RETURN(udp_rel->sess != NULL, PJ_EINVALIDOP);
+
     return pj_turn_session_bind_channel(udp_rel->sess, peer, addr_len);
 }
@@ -233,5 +263,5 @@
     do {
 	/* Report incoming packet to TURN session */
-	if (bytes_read > 0) {
+	if (bytes_read > 0 && udp_rel->sess) {
 	    pj_turn_session_on_rx_pkt(udp_rel->sess, udp_rel->pkt, 
 				      bytes_read, PJ_TRUE);
@@ -318,5 +348,9 @@
 	(*udp_rel->cb.on_state)(udp_rel, old_state, new_state);
     }
-}
-
-
+
+    if (new_state > PJ_TURN_STATE_READY) {
+	udp_rel->sess = NULL;
+    }
+}
+
+
Index: pjproject/trunk/pjnath/src/pjturn-client/client_main.c
===================================================================
--- pjproject/trunk/pjnath/src/pjturn-client/client_main.c	(revision 1867)
+++ pjproject/trunk/pjnath/src/pjturn-client/client_main.c	(revision 1867)
@@ -0,0 +1,546 @@
+/* $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 <pjnath.h>
+#include <pjlib-util.h>
+#include <pjlib.h>
+
+
+#define THIS_FILE	"client_main.c"
+#define LOCAL_PORT	1998
+#define BANDWIDTH	64		    /* -1 to disable */
+#define LIFETIME	600		    /* -1 to disable */
+#define REQ_TRANSPORT	-1		    /* 0: udp, 1: tcp, -1: disable */
+#define REQ_PORT_PROPS	-1		    /* -1 to disable */
+#define REQ_IP		0		    /* IP address string */
+
+//#define OPTIONS		PJ_STUN_NO_AUTHENTICATE
+#define OPTIONS		0
+
+
+struct peer
+{
+    pj_sock_t	sock;
+    pj_sockaddr	addr;
+};
+
+
+static struct global
+{
+    pj_caching_pool	 cp;
+    pj_pool_t		*pool;
+    pj_stun_config	 stun_config;
+    pj_thread_t		*thread;
+    pj_bool_t		 quit;
+
+    pj_turn_udp		*udp_rel;
+    pj_sockaddr		 relay_addr;
+
+    struct peer		 peer[2];
+} g;
+
+static struct options
+{
+    char    *srv_addr;
+    char    *srv_port;
+    char    *realm;
+    char    *user_name;
+    char    *password;
+    char    *nonce;
+    pj_bool_t use_fingerprint;
+} o;
+
+
+static int worker_thread(void *unused);
+static pj_status_t parse_addr(const char *input, pj_sockaddr_in *addr);
+static void turn_on_rx_data(pj_turn_udp *udp_rel,
+			    const pj_uint8_t *pkt,
+			    unsigned pkt_len,
+			    const pj_sockaddr_t *peer_addr,
+			    unsigned addr_len);
+static void turn_on_state(pj_turn_udp *udp_rel, pj_turn_state_t old_state,
+			  pj_turn_state_t new_state);
+
+
+static void my_perror(const char *title, pj_status_t status)
+{
+    char errmsg[PJ_ERR_MSG_SIZE];
+    pj_strerror(status, errmsg, sizeof(errmsg));
+
+    PJ_LOG(3,(THIS_FILE, "%s: %s", title, errmsg));
+}
+
+#define CHECK(expr)	status=expr; \
+			if (status!=PJ_SUCCESS) { \
+			    my_perror(#expr, status); \
+			    return status; \
+			}
+
+static int init()
+{
+    int i;
+    pj_status_t status;
+
+    CHECK( pj_init() );
+    CHECK( pjlib_util_init() );
+    CHECK( pjnath_init() );
+
+    /* Check that server is specified */
+    if (!o.srv_addr) {
+	printf("Error: server must be specified\n");
+	return PJ_EINVAL;
+    }
+
+    pj_caching_pool_init(&g.cp, &pj_pool_factory_default_policy, 0);
+
+    g.pool = pj_pool_create(&g.cp.factory, "main", 1000, 1000, NULL);
+
+    /* Init global STUN config */
+    pj_stun_config_init(&g.stun_config, &g.cp.factory, 0, NULL, NULL);
+
+    /* Create global timer heap */
+    CHECK( pj_timer_heap_create(g.pool, 1000, &g.stun_config.timer_heap) );
+
+    /* Create global ioqueue */
+    CHECK( pj_ioqueue_create(g.pool, 16, &g.stun_config.ioqueue) );
+
+    /* 
+     * Create peers
+     */
+    for (i=0; i<PJ_ARRAY_SIZE(g.peer); ++i) {
+	int len;
+	pj_sockaddr addr;
+	pj_uint16_t port;
+
+	CHECK( pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &g.peer[i].sock) );
+	CHECK( pj_sock_bind_in(g.peer[i].sock, 0, 0) );
+
+	len = sizeof(addr);
+	CHECK( pj_sock_getsockname(g.peer[i].sock, &addr, &len) );
+	port = pj_sockaddr_get_port(&g.peer[i].addr);
+
+	CHECK( pj_gethostip(pj_AF_INET(), &g.peer[i].addr) );
+	pj_sockaddr_set_port(&g.peer[0].addr, port);
+
+    }
+
+    /* Start the worker thread */
+    CHECK( pj_thread_create(g.pool, "stun", &worker_thread, NULL, 0, 0, &g.thread) );
+
+
+    return PJ_SUCCESS;
+}
+
+
+static int shutdown()
+{
+    unsigned i;
+
+    if (g.thread) {
+	g.quit = 1;
+	pj_thread_join(g.thread);
+	pj_thread_destroy(g.thread);
+	g.thread = NULL;
+    }
+    if (g.udp_rel) {
+	pj_turn_udp_destroy(g.udp_rel);
+	g.udp_rel = NULL;
+    }
+    for (i=0; i<PJ_ARRAY_SIZE(g.peer); ++i) {
+	if (g.peer[i].sock) {
+	    pj_sock_close(g.peer[i].sock);
+	    g.peer[i].sock = 0;
+	}
+    }
+    if (g.stun_config.timer_heap) {
+	pj_timer_heap_destroy(g.stun_config.timer_heap);
+	g.stun_config.timer_heap = NULL;
+    }
+    if (g.stun_config.ioqueue) {
+	pj_ioqueue_destroy(g.stun_config.ioqueue);
+	g.stun_config.ioqueue = NULL;
+    }
+    if (g.pool) {
+	pj_pool_release(g.pool);
+	g.pool = NULL;
+    }
+    pj_pool_factory_dump(&g.cp.factory, PJ_TRUE);
+    pj_caching_pool_destroy(&g.cp);
+
+    return PJ_SUCCESS;
+}
+
+
+static int worker_thread(void *unused)
+{
+    PJ_UNUSED_ARG(unused);
+
+    while (!g.quit) {
+	const pj_time_val delay = {0, 10};
+	int i;
+	pj_fd_set_t readset;
+
+	/* Poll ioqueue for the TURN client */
+	pj_ioqueue_poll(g.stun_config.ioqueue, &delay);
+
+	/* Poll the timer heap */
+	pj_timer_heap_poll(g.stun_config.timer_heap, NULL);
+
+	/* Poll peer sockets */
+	PJ_FD_ZERO(&readset);
+	for (i=0; i<PJ_ARRAY_SIZE(g.peer); ++i) {
+	    PJ_FD_SET(g.peer[i].sock, &readset);
+	}
+
+	if (pj_sock_select(64, &readset, NULL, NULL, &delay) <= 0)
+	    continue;
+
+	/* Handle incoming data on peer socket */
+	for (i=0; i<PJ_ARRAY_SIZE(g.peer); ++i) {
+	    char buf[128];
+	    pj_ssize_t len;
+	    pj_sockaddr src_addr;
+	    int src_addr_len;
+	    pj_status_t status;
+
+	    if (!PJ_FD_ISSET(g.peer[i].sock, &readset))
+		continue;
+
+	    len = sizeof(buf);
+	    src_addr_len = sizeof(src_addr);
+
+	    status = pj_sock_recvfrom(g.peer[i].sock, buf, &len, 0, 
+				      &src_addr, &src_addr_len);
+	    if (status != PJ_SUCCESS) {
+		my_perror("recvfrom error", status);
+	    } else {
+		char addrinfo[80];
+		pj_sockaddr_print(&src_addr, addrinfo, sizeof(addrinfo), 3);
+		PJ_LOG(3,(THIS_FILE, "Peer%d received %d bytes from %s: %.*s",
+			  i, len, addrinfo, len, buf));
+	    }
+	}
+    }
+
+    return 0;
+}
+
+static pj_status_t create_relay(void)
+{
+    pj_turn_udp_cb rel_cb;
+    pj_stun_auth_cred cred;
+    pj_str_t srv;
+    pj_status_t status;
+
+    if (g.udp_rel) {
+	PJ_LOG(1,(THIS_FILE, "Relay already created"));
+	return -1;
+    }
+
+    pj_bzero(&rel_cb, sizeof(rel_cb));
+    rel_cb.on_rx_data = &turn_on_rx_data;
+    rel_cb.on_state = &turn_on_state;
+    CHECK( pj_turn_udp_create(&g.stun_config, pj_AF_INET(), &rel_cb, 0,
+			      NULL, &g.udp_rel) );
+
+    if (o.user_name) {
+	pj_bzero(&cred, sizeof(cred));
+	cred.type = PJ_STUN_AUTH_CRED_STATIC;
+	cred.data.static_cred.realm = pj_str(o.realm);
+	cred.data.static_cred.username = pj_str(o.user_name);
+	cred.data.static_cred.data_type = 0;
+	cred.data.static_cred.data = pj_str(o.password);
+	cred.data.static_cred.nonce = pj_str(o.nonce);
+    } else {
+	PJ_LOG(2,(THIS_FILE, "Warning: no credential is set"));
+    }
+
+    srv = pj_str(o.srv_addr);
+    CHECK( pj_turn_udp_init(g.udp_rel,				 /* the relay */
+			    &srv,				 /* srv addr */
+			    (o.srv_port?atoi(o.srv_port):PJ_STUN_PORT),/* def port */
+			    NULL,				 /* resolver */
+			    (o.user_name?&cred:NULL),		 /* credential */
+			    NULL)				 /* alloc param */
+			    );
+
+    return PJ_SUCCESS;
+}
+
+static void destroy_relay(void)
+{
+    if (g.udp_rel) {
+	pj_turn_udp_destroy(g.udp_rel);
+	g.udp_rel = NULL;
+    }
+}
+
+
+static void turn_on_rx_data(pj_turn_udp *udp_rel,
+			    const pj_uint8_t *pkt,
+			    unsigned pkt_len,
+			    const pj_sockaddr_t *peer_addr,
+			    unsigned addr_len)
+{
+    char addrinfo[80];
+
+    pj_sockaddr_print(peer_addr, addrinfo, sizeof(addrinfo), 3);
+
+    PJ_LOG(3,(THIS_FILE, "Client received %d bytes data from %s: %.*s",
+	      pkt_len, addrinfo, pkt_len, pkt));
+}
+
+
+static void turn_on_state(pj_turn_udp *udp_rel, pj_turn_state_t old_state,
+			  pj_turn_state_t new_state)
+{
+    if (new_state == PJ_TURN_STATE_READY) {
+	pj_turn_session_info info;
+	pj_turn_udp_get_info(udp_rel, &info);
+	pj_memcpy(&g.relay_addr, &info.relay_addr, sizeof(pj_sockaddr));
+    }
+}
+
+static pj_status_t parse_addr(const char *input,
+			      pj_sockaddr_in *addr)
+{
+    const char *pos;
+    pj_str_t ip;
+    pj_uint16_t port;
+    pj_sockaddr tmp_addr;
+
+    pos = pj_ansi_strchr(input, ':');
+    if (pos==NULL) {
+	puts("Invalid format");
+	return -1;
+    }
+
+    ip.ptr = (char*)input;
+    ip.slen = pos - input;
+    port = (pj_uint16_t)atoi(pos+1);
+
+    if (port==0) {
+	puts("Invalid port");
+	return -1;
+    }
+
+    if (pj_sockaddr_in_init(&tmp_addr.ipv4, &ip, port)!=PJ_SUCCESS) {
+	puts("Invalid address");
+	return -1;
+    }
+
+    pj_memcpy(addr, &tmp_addr, sizeof(pj_sockaddr_in));
+
+    return PJ_SUCCESS;
+}
+
+static void menu(void)
+{
+    pj_turn_session_info info;
+    char client_state[20], relay_addr[80], peer0_addr[80], peer1_addr[80];
+
+    if (g.udp_rel) {
+	pj_turn_udp_get_info(g.udp_rel, &info);
+	strcpy(client_state, pj_turn_state_name(info.state));
+	pj_sockaddr_print(&info.relay_addr, relay_addr, sizeof(relay_addr), 3);
+    } else {
+	strcpy(client_state, "NULL");
+	strcpy(relay_addr, "0.0.0.0:0");
+    }
+
+    pj_sockaddr_print(&g.peer[0].addr, peer0_addr, sizeof(peer0_addr), 3);
+    pj_sockaddr_print(&g.peer[1].addr, peer1_addr, sizeof(peer1_addr), 3);
+
+
+    puts("\n");
+    puts("+====================================================================+");
+    puts("|             CLIENT                |             PEER-0             |");
+    puts("|                                   |                                |");
+    printf("| State     : %12s          | Address: %21s |\n",
+	   client_state, peer0_addr);
+    printf("| Relay addr: %21s |                                |\n",
+	   relay_addr);
+    puts("|                                   | 0  Send data to relay address  |");
+    puts("| A      Allocate relay             +--------------------------------+	");
+    puts("| S[01]  Send data to peer 0/1      |             PEER-1             |");
+    puts("| B[01]  BindChannel to peer 0/1    |                                |");
+    printf("| X      Delete allocation          | Address: %21s |\n",
+	  peer1_addr);
+    puts("+-----------------------------------+                                |");
+    puts("| q  Quit                           | 1  Send data to relay adderss  |");
+    puts("+-----------------------------------+--------------------------------+");
+    printf(">>> ");
+    fflush(stdout);
+}
+
+
+static void console_main(void)
+{
+    while (!g.quit) {
+	char input[32];
+	struct peer *peer;
+	pj_ssize_t len;
+	pj_status_t status;
+
+	menu();
+
+	fgets(input, sizeof(input), stdin);
+	
+	switch (input[0]) {
+	case 'A':
+	    create_relay();
+	    break;
+	case 'S':
+	    if (g.udp_rel == NULL) {
+		puts("Error: no relay");
+		continue;
+	    }
+	    if (input[1] != '0' && input[1] != '1') {
+		puts("Usage: S0 or S1");
+		continue;
+	    }
+	    peer = &g.peer[input[1]-'0'];
+	    strcpy(input, "Hello from client");
+	    status = pj_turn_udp_sendto(g.udp_rel, input, strlen(input)+1, 
+					&peer->addr, 
+					pj_sockaddr_get_len(&peer->addr));
+	    if (status != PJ_SUCCESS)
+		my_perror("turn_udp_sendto() failed", status);
+	    break;
+	case 'B':
+	    if (g.udp_rel == NULL) {
+		puts("Error: no relay");
+		continue;
+	    }
+	    if (input[1] != '0' && input[1] != '1') {
+		puts("Usage: B0 or B1");
+		continue;
+	    }
+	    peer = &g.peer[input[1]-'0'];
+	    status = pj_turn_udp_bind_channel(g.udp_rel, &peer->addr,
+					      pj_sockaddr_get_len(&peer->addr));
+	    if (status != PJ_SUCCESS)
+		my_perror("turn_udp_bind_channel() failed", status);
+	    break;
+	case 'X':
+	    if (g.udp_rel == NULL) {
+		puts("Error: no relay");
+		continue;
+	    }
+	    destroy_relay();
+	    break;
+	case '0':
+	case '1':
+	    peer = &g.peer[input[1]-'0'];
+	    sprintf(input, "Hello from peer%d", input[0]-'0');
+	    len = strlen(input)+1;
+	    pj_sock_sendto(peer->sock, input, &len, 0, &g.relay_addr, 
+			   pj_sockaddr_get_len(&g.relay_addr));
+	    break;
+	case 'q':
+	    g.quit = PJ_TRUE;
+	    break;
+	}
+    }
+}
+
+
+static void usage(void)
+{
+    puts("Usage: pjturn_client TARGET [OPTIONS]");
+    puts("");
+    puts("where TARGET is \"host[:port]\"");
+    puts("");
+    puts("and OPTIONS:");
+    puts(" --realm, -r       Set realm of the credential");
+    puts(" --username, -u    Set username of the credential");
+    puts(" --password, -p    Set password of the credential");
+    puts(" --nonce, -N       Set NONCE");   
+    puts(" --fingerprint, -F Use fingerprint for outgoing requests");
+    puts(" --help, -h");
+}
+
+int main(int argc, char *argv[])
+{
+    struct pj_getopt_option long_options[] = {
+	{ "realm",	1, 0, 'r'},
+	{ "username",	1, 0, 'u'},
+	{ "password",	1, 0, 'p'},
+	{ "nonce",	1, 0, 'N'},
+	{ "fingerprint",0, 0, 'F'},
+	{ "data",	1, 0, 'D'},
+	{ "help",	0, 0, 'h'}
+    };
+    int c, opt_id;
+    char *pos;
+    pj_status_t status;
+
+    while((c=pj_getopt_long(argc,argv, "r:u:p:N:hF", long_options, &opt_id))!=-1) {
+	switch (c) {
+	case 'r':
+	    o.realm = pj_optarg;
+	    break;
+	case 'u':
+	    o.user_name = pj_optarg;
+	    break;
+	case 'p':
+	    o.password = pj_optarg;
+	    break;
+	case 'N':
+	    o.nonce = pj_optarg;
+	    break;
+	case 'h':
+	    usage();
+	    return 0;
+	case 'F':
+	    o.use_fingerprint = PJ_TRUE;
+	    break;
+
+	default:
+	    printf("Argument \"%s\" is not valid. Use -h to see help",
+		   argv[pj_optind]);
+	    return 1;
+	}
+    }
+
+    if (pj_optind == argc) {
+	puts("Error: TARGET is needed");
+	return 1;
+    }
+
+    if ((pos=pj_ansi_strchr(argv[pj_optind], ':')) != NULL) {
+	o.srv_addr = argv[pj_optind];
+	*pos = '\0';
+	o.srv_port = pos+1;
+    } else {
+	o.srv_addr = argv[pj_optind];
+    }
+
+    if ((status=init()) != 0)
+	goto on_return;
+    
+    if ((status=create_relay()) != 0)
+	goto on_return;
+    
+    console_main();
+
+on_return:
+    shutdown();
+    return status ? 1 : 0;
+}
+
