summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pjlib-util/build/Makefile2
-rw-r--r--pjlib-util/build/pjlib_util.dsp35
-rw-r--r--pjlib-util/build/wince-evc4/pjlib_util_wince.vcp1826
-rw-r--r--pjlib-util/include/pjlib-util.h1
-rw-r--r--pjlib-util/include/pjlib-util/dns.h164
-rw-r--r--pjlib-util/include/pjlib-util/errno.h113
-rw-r--r--pjlib-util/include/pjlib-util/resolver.h520
-rw-r--r--pjlib-util/src/pjlib-util/dns.c257
-rw-r--r--pjlib-util/src/pjlib-util/dns_dump.c96
-rw-r--r--pjlib-util/src/pjlib-util/errno.c23
-rw-r--r--pjlib-util/src/pjlib-util/resolver.c1408
-rw-r--r--pjlib/src/pj/pool_buf.c3
-rw-r--r--pjsip-apps/src/pjsua/pjsua_app.c13
-rw-r--r--pjsip/build/Makefile3
-rw-r--r--pjsip/build/test_pjsip.dsp4
-rw-r--r--pjsip/include/pjsip/sip_config.h36
-rw-r--r--pjsip/include/pjsip/sip_endpoint.h43
-rw-r--r--pjsip/include/pjsip/sip_resolve.h193
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h14
-rw-r--r--pjsip/src/pjsip/sip_endpoint.c47
-rw-r--r--pjsip/src/pjsip/sip_resolve.c848
-rw-r--r--pjsip/src/pjsua-lib/pjsua_core.c39
-rw-r--r--pjsip/src/test-pjsip/dns_test.c596
-rw-r--r--pjsip/src/test-pjsip/test.c10
-rw-r--r--pjsip/src/test-pjsip/test.h4
25 files changed, 6060 insertions, 238 deletions
diff --git a/pjlib-util/build/Makefile b/pjlib-util/build/Makefile
index 3c7be4f4..a5d8c925 100644
--- a/pjlib-util/build/Makefile
+++ b/pjlib-util/build/Makefile
@@ -26,7 +26,7 @@ export _LDFLAGS := $(subst /,$(HOST_PSEP),$(PJLIB_UTIL_LIB)) \
#
export PJLIB_UTIL_SRCDIR = ../src/pjlib-util
export PJLIB_UTIL_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
- errno.o dns.o dns_dump.o getopt.o md5.o \
+ errno.o dns.o dns_dump.o getopt.o md5.o resolver.o \
scanner.o stun.o string.o stun.o stun_client.o xml.o
export PJLIB_UTIL_CFLAGS += $(_CFLAGS)
diff --git a/pjlib-util/build/pjlib_util.dsp b/pjlib-util/build/pjlib_util.dsp
index 56dac412..a8722e69 100644
--- a/pjlib-util/build/pjlib_util.dsp
+++ b/pjlib-util/build/pjlib_util.dsp
@@ -41,7 +41,8 @@ RSC=rc.exe
# PROP Intermediate_Dir "./output/pjlib-util-i386-win32-vc6-release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
-# ADD CPP /nologo /MD /W4 /GX /Zi /O2 /Ob2 /I "../include" /I "../../pjlib/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /c
+# ADD CPP /nologo /MD /W4 /GX /Zi /O2 /Ob2 /I "../include" /I "../../pjlib/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /c
+# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
@@ -64,7 +65,8 @@ LIB32=link.exe -lib
# PROP Intermediate_Dir "./output/pjlib-util-i386-win32-vc6-debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /GZ /c
+# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
@@ -86,10 +88,24 @@ LIB32=link.exe -lib
# Begin Source File
SOURCE="..\src\pjlib-util\dns.c"
+
+!IF "$(CFG)" == "pjlib_util - Win32 Release"
+
+!ELSEIF "$(CFG)" == "pjlib_util - Win32 Debug"
+
+!ENDIF
+
# End Source File
# Begin Source File
SOURCE="..\src\pjlib-util\dns_dump.c"
+
+!IF "$(CFG)" == "pjlib_util - Win32 Release"
+
+!ELSEIF "$(CFG)" == "pjlib_util - Win32 Debug"
+
+!ENDIF
+
# End Source File
# Begin Source File
@@ -105,6 +121,17 @@ SOURCE="..\src\pjlib-util\md5.c"
# End Source File
# Begin Source File
+SOURCE="..\src\pjlib-util\resolver.c"
+
+!IF "$(CFG)" == "pjlib_util - Win32 Release"
+
+!ELSEIF "$(CFG)" == "pjlib_util - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
SOURCE="..\src\pjlib-util\scanner.c"
# End Source File
# Begin Source File
@@ -163,6 +190,10 @@ SOURCE="..\include\pjlib-util.h"
# End Source File
# Begin Source File
+SOURCE="..\include\pjlib-util\resolver.h"
+# End Source File
+# Begin Source File
+
SOURCE="..\include\pjlib-util\scanner.h"
# End Source File
# Begin Source File
diff --git a/pjlib-util/build/wince-evc4/pjlib_util_wince.vcp b/pjlib-util/build/wince-evc4/pjlib_util_wince.vcp
index fa7e155a..953b54b8 100644
--- a/pjlib-util/build/wince-evc4/pjlib_util_wince.vcp
+++ b/pjlib-util/build/wince-evc4/pjlib_util_wince.vcp
@@ -1659,6 +1659,8 @@ DEP_CPP_DNS_C=\
"..\..\..\pjlib\include\pj\compat\ctype.h"\
"..\..\..\pjlib\include\pj\compat\errno.h"\
"..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
"..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
"..\..\..\pjlib\include\pj\compat\os_linux.h"\
"..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
@@ -2505,10 +2507,17 @@ DEP_CPP_DNS_D=\
!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Release"
DEP_CPP_DNS_D=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
"..\..\..\pjlib\include\pj\assert.h"\
"..\..\..\pjlib\include\pj\compat\assert.h"\
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
"..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
"..\..\..\pjlib\include\pj\compat\os_linux.h"\
"..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
@@ -2517,12 +2526,40 @@ DEP_CPP_DNS_D=\
"..\..\..\pjlib\include\pj\compat\os_sunos.h"\
"..\..\..\pjlib\include\pj\compat\os_win32.h"\
"..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
"..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
"..\..\..\pjlib\include\pj\config.h"\
"..\..\..\pjlib\include\pj\config_site.h"\
"..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
"..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
"..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
"..\..\include\pjlib-util\dns.h"\
@@ -3316,16 +3353,17 @@ DEP_CPP_ERRNO=\
!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Release"
DEP_CPP_ERRNO=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
"..\..\..\pjlib\include\pj\compat\errno.h"\
- "..\..\..\pjlib\include\pj\compat\m_alpha.h"\
- "..\..\..\pjlib\include\pj\compat\m_armv4.h"\
- "..\..\..\pjlib\include\pj\compat\m_i386.h"\
- "..\..\..\pjlib\include\pj\compat\m_m68k.h"\
- "..\..\..\pjlib\include\pj\compat\m_powerpc.h"\
- "..\..\..\pjlib\include\pj\compat\m_sparc.h"\
- "..\..\..\pjlib\include\pj\compat\m_x86_64.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
"..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
"..\..\..\pjlib\include\pj\compat\os_linux.h"\
"..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
@@ -3334,19 +3372,40 @@ DEP_CPP_ERRNO=\
"..\..\..\pjlib\include\pj\compat\os_sunos.h"\
"..\..\..\pjlib\include\pj\compat\os_win32.h"\
"..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
"..\..\..\pjlib\include\pj\compat\size_t.h"\
"..\..\..\pjlib\include\pj\compat\string.h"\
"..\..\..\pjlib\include\pj\config.h"\
"..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
"..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
"..\..\..\pjlib\include\pj\list.h"\
"..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
"..\..\..\pjlib\include\pj\pool.h"\
"..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
"..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
"..\..\..\pjlib\include\pj\string.h"\
"..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
"..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
"..\..\include\pjlib-util\errno.h"\
@@ -4201,15 +4260,17 @@ DEP_CPP_GETOP=\
!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Release"
DEP_CPP_GETOP=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
- "..\..\..\pjlib\include\pj\compat\m_alpha.h"\
- "..\..\..\pjlib\include\pj\compat\m_armv4.h"\
- "..\..\..\pjlib\include\pj\compat\m_i386.h"\
- "..\..\..\pjlib\include\pj\compat\m_m68k.h"\
- "..\..\..\pjlib\include\pj\compat\m_powerpc.h"\
- "..\..\..\pjlib\include\pj\compat\m_sparc.h"\
- "..\..\..\pjlib\include\pj\compat\m_x86_64.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
"..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
"..\..\..\pjlib\include\pj\compat\os_linux.h"\
"..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
@@ -4218,18 +4279,40 @@ DEP_CPP_GETOP=\
"..\..\..\pjlib\include\pj\compat\os_sunos.h"\
"..\..\..\pjlib\include\pj\compat\os_win32.h"\
"..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
"..\..\..\pjlib\include\pj\compat\size_t.h"\
"..\..\..\pjlib\include\pj\compat\string.h"\
"..\..\..\pjlib\include\pj\config.h"\
"..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
"..\..\..\pjlib\include\pj\list.h"\
"..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
"..\..\..\pjlib\include\pj\pool.h"\
"..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
"..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
"..\..\..\pjlib\include\pj\string.h"\
"..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
"..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
"..\..\include\pjlib-util\getopt.h"\
@@ -5055,36 +5138,61 @@ NODEP_CPP_MD5_C=\
!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Release"
DEP_CPP_MD5_C=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
- "..\..\..\pjlib\include\pj\compat\m_alpha.h"\
- "..\..\..\pjlib\include\pj\compat\m_armv4.h"\
- "..\..\..\pjlib\include\pj\compat\m_i386.h"\
- "..\..\..\pjlib\include\pj\compat\m_m68k.h"\
- "..\..\..\pjlib\include\pj\compat\m_sparc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
"..\..\..\pjlib\include\pj\compat\os_linux.h"\
"..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
"..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
"..\..\..\pjlib\include\pj\compat\os_sunos.h"\
"..\..\..\pjlib\include\pj\compat\os_win32.h"\
"..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
"..\..\..\pjlib\include\pj\compat\size_t.h"\
"..\..\..\pjlib\include\pj\compat\string.h"\
"..\..\..\pjlib\include\pj\config.h"\
"..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
"..\..\..\pjlib\include\pj\list.h"\
"..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
"..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
"..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
"..\..\..\pjlib\include\pj\string.h"\
"..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
"..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
"..\..\include\pjlib-util\md5.h"\
-NODEP_CPP_MD5_C=\
- "..\..\..\pjlib\include\pj\compat\sprintf.h"\
- "..\..\..\pjlib\include\pj\compat\vsprintf.h"\
-
!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Debug"
@@ -5330,6 +5438,1477 @@ DEP_CPP_MD5_C=\
# End Source File
# Begin Source File
+SOURCE="..\..\src\pjlib-util\resolver.c"
+
+!IF "$(CFG)" == "pjlib_util_wince - Win32 (WCE MIPSII_FP) Release"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE MIPSII_FP) Debug"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE MIPSII) Release"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE MIPSII) Debug"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE SH4) Release"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE SH4) Debug"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE SH3) Release"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE SH3) Debug"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE MIPSIV) Release"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE MIPSIV) Debug"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE emulator) Release"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE emulator) Debug"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4I) Release"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4I) Debug"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE MIPSIV_FP) Release"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE MIPSIV_FP) Debug"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Release"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Debug"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE MIPS16) Release"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE MIPS16) Debug"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4T) Release"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4T) Debug"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE x86) Release"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE x86) Debug"
+
+DEP_CPP_RESOL=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\compat\string.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
+ "..\..\..\pjlib\include\pj\list.h"\
+ "..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
+ "..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
+ "..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
+ "..\..\..\pjlib\include\pj\string.h"\
+ "..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\dns.h"\
+ "..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\resolver.h"\
+
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
SOURCE="..\..\src\pjlib-util\scanner.c"
!IF "$(CFG)" == "pjlib_util_wince - Win32 (WCE MIPSII_FP) Release"
@@ -6071,19 +7650,22 @@ NODEP_CPP_SCANN=\
!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Release"
DEP_CPP_SCANN=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
"..\..\..\pjlib\include\pj\assert.h"\
"..\..\..\pjlib\include\pj\compat\assert.h"\
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
"..\..\..\pjlib\include\pj\compat\errno.h"\
- "..\..\..\pjlib\include\pj\compat\m_alpha.h"\
- "..\..\..\pjlib\include\pj\compat\m_armv4.h"\
- "..\..\..\pjlib\include\pj\compat\m_i386.h"\
- "..\..\..\pjlib\include\pj\compat\m_m68k.h"\
- "..\..\..\pjlib\include\pj\compat\m_sparc.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
"..\..\..\pjlib\include\pj\compat\os_linux.h"\
"..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
"..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
"..\..\..\pjlib\include\pj\compat\os_sunos.h"\
"..\..\..\pjlib\include\pj\compat\os_win32.h"\
"..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
@@ -6092,26 +7674,41 @@ DEP_CPP_SCANN=\
"..\..\..\pjlib\include\pj\compat\string.h"\
"..\..\..\pjlib\include\pj\config.h"\
"..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
"..\..\..\pjlib\include\pj\errno.h"\
"..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
"..\..\..\pjlib\include\pj\list.h"\
"..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
"..\..\..\pjlib\include\pj\os.h"\
"..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
"..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
"..\..\..\pjlib\include\pj\string.h"\
"..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
"..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
"..\..\include\pjlib-util\scanner.h"\
"..\..\include\pjlib-util\scanner_cis_bitwise.h"\
"..\..\include\pjlib-util\scanner_cis_uint.h"\
"..\..\src\pjlib-util\scanner_cis_bitwise.c"\
"..\..\src\pjlib-util\scanner_cis_uint.c"\
-NODEP_CPP_SCANN=\
- "..\..\..\pjlib\include\pj\compat\sprintf.h"\
- "..\..\..\pjlib\include\pj\compat\vsprintf.h"\
-
!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Debug"
@@ -7086,41 +8683,64 @@ NODEP_CPP_STRIN=\
!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Release"
DEP_CPP_STRIN=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
"..\..\..\pjlib\include\pj\compat\ctype.h"\
- "..\..\..\pjlib\include\pj\compat\m_alpha.h"\
- "..\..\..\pjlib\include\pj\compat\m_armv4.h"\
- "..\..\..\pjlib\include\pj\compat\m_i386.h"\
- "..\..\..\pjlib\include\pj\compat\m_m68k.h"\
- "..\..\..\pjlib\include\pj\compat\m_sparc.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
"..\..\..\pjlib\include\pj\compat\os_linux.h"\
"..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
"..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
"..\..\..\pjlib\include\pj\compat\os_sunos.h"\
"..\..\..\pjlib\include\pj\compat\os_win32.h"\
"..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
"..\..\..\pjlib\include\pj\compat\size_t.h"\
"..\..\..\pjlib\include\pj\compat\string.h"\
"..\..\..\pjlib\include\pj\config.h"\
"..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
"..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
"..\..\..\pjlib\include\pj\list.h"\
"..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
+ "..\..\..\pjlib\include\pj\log.h"\
+ "..\..\..\pjlib\include\pj\os.h"\
"..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
"..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
"..\..\..\pjlib\include\pj\string.h"\
"..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
"..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
"..\..\include\pjlib-util\scanner.h"\
"..\..\include\pjlib-util\scanner_cis_bitwise.h"\
"..\..\include\pjlib-util\scanner_cis_uint.h"\
"..\..\include\pjlib-util\string.h"\
-NODEP_CPP_STRIN=\
- "..\..\..\pjlib\include\pj\compat\sprintf.h"\
- "..\..\..\pjlib\include\pj\compat\vsprintf.h"\
-
!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Debug"
@@ -8019,39 +9639,62 @@ NODEP_CPP_STUN_=\
!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Release"
DEP_CPP_STUN_=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
- "..\..\..\pjlib\include\pj\compat\m_alpha.h"\
- "..\..\..\pjlib\include\pj\compat\m_armv4.h"\
- "..\..\..\pjlib\include\pj\compat\m_i386.h"\
- "..\..\..\pjlib\include\pj\compat\m_m68k.h"\
- "..\..\..\pjlib\include\pj\compat\m_sparc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
"..\..\..\pjlib\include\pj\compat\os_linux.h"\
"..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
"..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
"..\..\..\pjlib\include\pj\compat\os_sunos.h"\
"..\..\..\pjlib\include\pj\compat\os_win32.h"\
"..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
"..\..\..\pjlib\include\pj\compat\size_t.h"\
"..\..\..\pjlib\include\pj\compat\string.h"\
"..\..\..\pjlib\include\pj\config.h"\
"..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
"..\..\..\pjlib\include\pj\list.h"\
"..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
"..\..\..\pjlib\include\pj\log.h"\
"..\..\..\pjlib\include\pj\os.h"\
"..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
"..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
"..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
"..\..\..\pjlib\include\pj\string.h"\
"..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
"..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\errno.h"\
"..\..\include\pjlib-util\stun.h"\
-NODEP_CPP_STUN_=\
- "..\..\..\pjlib\include\pj\compat\sprintf.h"\
- "..\..\..\pjlib\include\pj\compat\vsprintf.h"\
-
!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Debug"
@@ -8954,40 +10597,62 @@ NODEP_CPP_STUN_C=\
!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Release"
DEP_CPP_STUN_C=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
- "..\..\..\pjlib\include\pj\compat\m_alpha.h"\
- "..\..\..\pjlib\include\pj\compat\m_armv4.h"\
- "..\..\..\pjlib\include\pj\compat\m_i386.h"\
- "..\..\..\pjlib\include\pj\compat\m_m68k.h"\
- "..\..\..\pjlib\include\pj\compat\m_sparc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
"..\..\..\pjlib\include\pj\compat\os_linux.h"\
"..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
"..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
"..\..\..\pjlib\include\pj\compat\os_sunos.h"\
"..\..\..\pjlib\include\pj\compat\os_win32.h"\
"..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\setjmp.h"\
"..\..\..\pjlib\include\pj\compat\size_t.h"\
"..\..\..\pjlib\include\pj\compat\string.h"\
"..\..\..\pjlib\include\pj\config.h"\
"..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
+ "..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
"..\..\..\pjlib\include\pj\list.h"\
"..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
"..\..\..\pjlib\include\pj\log.h"\
"..\..\..\pjlib\include\pj\os.h"\
"..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
"..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
"..\..\..\pjlib\include\pj\sock.h"\
"..\..\..\pjlib\include\pj\sock_select.h"\
"..\..\..\pjlib\include\pj\string.h"\
"..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
"..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
+ "..\..\include\pjlib-util\errno.h"\
"..\..\include\pjlib-util\stun.h"\
-NODEP_CPP_STUN_C=\
- "..\..\..\pjlib\include\pj\compat\sprintf.h"\
- "..\..\..\pjlib\include\pj\compat\vsprintf.h"\
-
!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Debug"
@@ -9944,16 +11609,22 @@ NODEP_CPP_XML_C=\
!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Release"
DEP_CPP_XML_C=\
+ "..\..\..\pjlib\include\pj\addr_resolv.h"\
+ "..\..\..\pjlib\include\pj\array.h"\
+ "..\..\..\pjlib\include\pj\assert.h"\
+ "..\..\..\pjlib\include\pj\compat\assert.h"\
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
- "..\..\..\pjlib\include\pj\compat\m_alpha.h"\
- "..\..\..\pjlib\include\pj\compat\m_armv4.h"\
- "..\..\..\pjlib\include\pj\compat\m_i386.h"\
- "..\..\..\pjlib\include\pj\compat\m_m68k.h"\
- "..\..\..\pjlib\include\pj\compat\m_sparc.h"\
+ "..\..\..\pjlib\include\pj\compat\ctype.h"\
+ "..\..\..\pjlib\include\pj\compat\errno.h"\
+ "..\..\..\pjlib\include\pj\compat\high_precision.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
"..\..\..\pjlib\include\pj\compat\os_linux.h"\
"..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
"..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
"..\..\..\pjlib\include\pj\compat\os_sunos.h"\
"..\..\..\pjlib\include\pj\compat\os_win32.h"\
"..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
@@ -9962,25 +11633,40 @@ DEP_CPP_XML_C=\
"..\..\..\pjlib\include\pj\compat\string.h"\
"..\..\..\pjlib\include\pj\config.h"\
"..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\ctype.h"\
+ "..\..\..\pjlib\include\pj\errno.h"\
"..\..\..\pjlib\include\pj\except.h"\
+ "..\..\..\pjlib\include\pj\fifobuf.h"\
+ "..\..\..\pjlib\include\pj\file_access.h"\
+ "..\..\..\pjlib\include\pj\file_io.h"\
+ "..\..\..\pjlib\include\pj\guid.h"\
+ "..\..\..\pjlib\include\pj\hash.h"\
+ "..\..\..\pjlib\include\pj\ioqueue.h"\
"..\..\..\pjlib\include\pj\list.h"\
"..\..\..\pjlib\include\pj\list_i.h"\
+ "..\..\..\pjlib\include\pj\lock.h"\
"..\..\..\pjlib\include\pj\log.h"\
"..\..\..\pjlib\include\pj\os.h"\
"..\..\..\pjlib\include\pj\pool.h"\
+ "..\..\..\pjlib\include\pj\pool_alt.h"\
+ "..\..\..\pjlib\include\pj\pool_buf.h"\
"..\..\..\pjlib\include\pj\pool_i.h"\
+ "..\..\..\pjlib\include\pj\rand.h"\
+ "..\..\..\pjlib\include\pj\rbtree.h"\
+ "..\..\..\pjlib\include\pj\sock.h"\
+ "..\..\..\pjlib\include\pj\sock_select.h"\
"..\..\..\pjlib\include\pj\string.h"\
"..\..\..\pjlib\include\pj\string_i.h"\
+ "..\..\..\pjlib\include\pj\timer.h"\
"..\..\..\pjlib\include\pj\types.h"\
+ "..\..\..\pjlib\include\pj\unicode.h"\
+ "..\..\..\pjlib\include\pjlib.h"\
"..\..\include\pjlib-util\scanner.h"\
"..\..\include\pjlib-util\scanner_cis_bitwise.h"\
"..\..\include\pjlib-util\scanner_cis_uint.h"\
"..\..\include\pjlib-util\xml.h"\
-NODEP_CPP_XML_C=\
- "..\..\..\pjlib\include\pj\compat\sprintf.h"\
- "..\..\..\pjlib\include\pj\compat\vsprintf.h"\
-
!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Debug"
@@ -10299,6 +11985,10 @@ SOURCE="..\..\include\pjlib-util.h"
# End Source File
# Begin Source File
+SOURCE="..\..\include\pjlib-util\resolver.h"
+# End Source File
+# Begin Source File
+
SOURCE="..\..\include\pjlib-util\scanner.h"
# End Source File
# Begin Source File
diff --git a/pjlib-util/include/pjlib-util.h b/pjlib-util/include/pjlib-util.h
index 741578fd..3ac8c50b 100644
--- a/pjlib-util/include/pjlib-util.h
+++ b/pjlib-util/include/pjlib-util.h
@@ -23,6 +23,7 @@
#include <pjlib-util/errno.h>
#include <pjlib-util/getopt.h>
#include <pjlib-util/md5.h>
+#include <pjlib-util/resolver.h>
#include <pjlib-util/scanner.h>
#include <pjlib-util/stun.h>
#include <pjlib-util/xml.h>
diff --git a/pjlib-util/include/pjlib-util/dns.h b/pjlib-util/include/pjlib-util/dns.h
index cb6a28f2..d431b0da 100644
--- a/pjlib-util/include/pjlib-util/dns.h
+++ b/pjlib-util/include/pjlib-util/dns.h
@@ -22,7 +22,7 @@
/**
* @file dns.h
- * @brief Asynchronous DNS Name Resolution/resolver
+ * @brief Low level DNS message parsing and packetization.
*/
#include <pj/types.h>
@@ -31,16 +31,35 @@ PJ_BEGIN_DECL
/**
- * @defgroup PJ_DNS_RESOLVER Asynchronous DNS Name Resolution/resolver
+ * @defgroup PJ_DNS Low-level DNS message parsing and packetization
* @ingroup PJ
* @{
*
- * This module provides services to performing asynchronous DNS resolution.
+ * This module provides low-level services to parse and packetize DNS queries
+ * and responses. The functions support building a DNS query packet and parse
+ * the data in the DNS response.
+ *
+ * To create a DNS query packet, application should call #pj_dns_make_query()
+ * function, specifying the desired DNS query type, the name to be resolved,
+ * and the buffer where the DNS packet will be built into.
+ *
+ * When incoming DNS query or response packet arrives, application can use
+ * #pj_dns_parse_packet() to parse the TCP/UDP payload into parsed DNS packet
+ * structure.
+ *
+ * This module does not provide any networking functionalities to send or
+ * receive DNS packets. This functionality should be provided by higher layer
+ * modules such as @ref PJ_DNS_RESOLVER.
*/
+enum
+{
+ PJ_DNS_CLASS_IN = 1 /**< DNS class IN. */
+};
+
/**
* This enumeration describes standard DNS record types as described by
- * RFC 1035.
+ * RFC 1035, RFC 2782, and others.
*/
typedef enum pj_dns_type
{
@@ -158,31 +177,69 @@ typedef struct pj_dns_hdr
#define PJ_DNS_GET_QR(val) (((val) & PJ_DNS_SET_QR(1)) >> 15)
+/**
+ * These constants describe DNS RCODEs. Application can fold these constants
+ * into PJLIB pj_status_t namespace by calling #PJ_STATUS_FROM_DNS_RCODE()
+ * macro.
+ */
+typedef enum pj_dns_rcode
+{
+ PJ_DNS_RCODE_FORMERR = 1, /**< Format error. */
+ PJ_DNS_RCODE_SERVFAIL = 2, /**< Server failure. */
+ PJ_DNS_RCODE_NXDOMAIN = 3, /**< Name Error. */
+ PJ_DNS_RCODE_NOTIMPL = 4, /**< Not Implemented. */
+ PJ_DNS_RCODE_REFUSED = 5, /**< Refused. */
+ PJ_DNS_RCODE_YXDOMAIN = 6, /**< The name exists. */
+ PJ_DNS_RCODE_YXRRSET = 7, /**< The RRset (name, type) exists. */
+ PJ_DNS_RCODE_NXRRSET = 8, /**< The RRset (name, type) doesn't exist*/
+ PJ_DNS_RCODE_NOTAUTH = 9, /**< Not authorized. */
+ PJ_DNS_RCODE_NOTZONE = 10 /**< The zone specified is not a zone. */
+
+} pj_dns_rcode;
+
/**
- * This constants describes record types in the DNS packet.
+ * This constant specifies the maximum names to keep in the temporary name
+ * table when performing name compression scheme when duplicating DNS packet
+ * (the #pj_dns_packet_dup() function).
+ *
+ * Generally name compression is desired, since it saves some memory (see
+ * PJ_DNS_RESOLVER_RES_BUF_SIZE setting). However it comes at the expense of
+ * a little processing overhead to perform name scanning and also a little
+ * bit more stack usage (8 bytes per entry on 32bit platform).
+ *
+ * Default: 16
*/
-typedef enum pj_dns_rec_type
+#ifndef PJ_DNS_MAX_NAMES_IN_NAMETABLE
+# define PJ_DNS_MAX_NAMES_IN_NAMETABLE 16
+#endif
+
+
+/**
+ * This structure describes a DNS query record.
+ */
+typedef struct pj_dns_parsed_query
{
- DNS_QUERY_REC, /**< The record is a query record */
- DNS_RR_REC, /**< The record is resource record */
- DNS_NS_REC, /**< The record is name server record */
- DNS_REC_AR, /**< The record is additional RR. */
-} pj_dns_rec_type;
+ pj_str_t name; /**< The domain in the query. */
+ pj_uint16_t type; /**< Type of the query (pj_dns_type) */
+ pj_uint16_t dnsclass; /**< Network class (PJ_DNS_CLASS_IN=1) */
+} pj_dns_parsed_query;
/**
- * This structure describes a Resource Record parsed from the DNS response.
+ * This structure describes a Resource Record parsed from the DNS packet.
* All integral values are in host byte order.
*/
typedef struct pj_dns_parsed_rr
{
pj_str_t name; /**< The domain name which this rec pertains. */
pj_uint16_t type; /**< RR type code. */
- pj_uint16_t class_; /**< Class of data (normally 1, for IN). */
+ pj_uint16_t dnsclass; /**< Class of data (PJ_DNS_CLASS_IN=1). */
pj_uint32_t ttl; /**< Time to live. */
pj_uint16_t rdlength; /**< Resource data length. */
- void *data; /**< Pointer to the raw resource data. */
+ void *data; /**< Pointer to the raw resource data, only
+ when the type is not known. If it is known,
+ the data will be put in rdata below. */
/** For resource types that are recognized/supported by this library,
* the parsed resource data will be placed in this rdata union.
@@ -223,21 +280,29 @@ typedef struct pj_dns_parsed_rr
/**
- * This structure describes the response parsed from the raw DNS response.
- * Note that all integral values in the parsed response are represented in
+ * This structure describes the parsed repersentation of the raw DNS packet.
+ * Note that all integral values in the parsed packet are represented in
* host byte order.
*/
-typedef struct pj_dns_parsed_response
+typedef struct pj_dns_parsed_packet
{
- pj_dns_hdr hdr; /**< Pointer to DNS hdr, in host byte order */
- pj_dns_parsed_rr *ans; /**< Array of DNS RR answer. */
- pj_dns_parsed_rr *ns; /**< Array of NS record in the answer. */
- pj_dns_parsed_rr *arr; /**< Array of additional RR answer. */
-} pj_dns_parsed_response;
+ pj_dns_hdr hdr; /**< Pointer to DNS hdr, in host byte order */
+ pj_dns_parsed_query *q; /**< Array of DNS queries. */
+ pj_dns_parsed_rr *ans; /**< Array of DNS RR answer. */
+ pj_dns_parsed_rr *ns; /**< Array of NS record in the answer. */
+ pj_dns_parsed_rr *arr; /**< Array of additional RR answer. */
+} pj_dns_parsed_packet;
/**
- * Create DNS query packet to resolve the specified names.
+ * Create DNS query packet to resolve the specified names. This function
+ * can be used to build any types of DNS query, such as A record or DNS SRV
+ * record.
+ *
+ * Application specifies the type of record and the name to be queried,
+ * and the function will build the DNS query packet into the buffer
+ * specified. Once the packet is successfully built, application can send
+ * the packet via TCP or UDP connection.
*
* @param packet The buffer to put the DNS query packet.
* @param size On input, it specifies the size of the buffer.
@@ -245,7 +310,7 @@ typedef struct pj_dns_parsed_response
* the DNS query packet.
* @param id DNS query ID to associate DNS response with the
* query.
- * @param qtype DNS type of record to be queried.
+ * @param qtype DNS type of record to be queried (see #pj_dns_type).
* @param name Name to be queried from the DNS server.
*
* @return PJ_SUCCESS on success, or the appropriate error code.
@@ -253,30 +318,55 @@ typedef struct pj_dns_parsed_response
PJ_DECL(pj_status_t) pj_dns_make_query(void *packet,
unsigned *size,
pj_uint16_t id,
- pj_dns_type qtype,
+ int qtype,
const pj_str_t *name);
/**
- * Parse raw DNS response packet into DNS response structure.
+ * Parse raw DNS packet into parsed DNS packet structure. This function is
+ * able to parse few DNS resource records such as A record, PTR record,
+ * CNAME record, NS record, and SRV record.
*
- * @param pool Pool to allocate memory for the parsed response.
- * @param packet
- * @param size
- * @param p_res
+ * @param pool Pool to allocate memory for the parsed packet.
+ * @param packet Pointer to the DNS packet (the TCP/UDP payload of
+ * the raw packet).
+ * @param size The size of the DNS packet.
+ * @param p_res Pointer to store the resulting parsed packet.
*
* @return PJ_SUCCESS on success, or the appropriate error code.
*/
-PJ_DECL(pj_status_t) pj_dns_parse_response(pj_pool_t *pool,
- const void *packet,
- unsigned size,
- pj_dns_parsed_response **p_res);
+PJ_DECL(pj_status_t) pj_dns_parse_packet(pj_pool_t *pool,
+ const void *packet,
+ unsigned size,
+ pj_dns_parsed_packet **p_res);
+
+/**
+ * Duplicate DNS packet.
+ *
+ * @param pool The pool to allocate memory for the duplicated packet.
+ * @param p The DNS packet to be cloned.
+ * @p_dst Pointer to store the cloned DNS packet.
+ */
+PJ_DECL(void) pj_dns_packet_dup(pj_pool_t *pool,
+ const pj_dns_parsed_packet*p,
+ pj_dns_parsed_packet **p_dst);
+
+
+/**
+ * Utility function to get the type name string of the specified DNS type.
+ *
+ * @param type DNS type (see #pj_dns_type).
+ *
+ * @return String name of the type (e.g. "A", "SRV", etc.).
+ */
+PJ_DECL(const char *) pj_dns_get_type_name(int type);
+
/**
- * Dump DNS response to standard log.
+ * Dump DNS packet to standard log.
*
- * @param res The DNS response.
+ * @param res The DNS packet.
*/
-PJ_DECL(void) pj_dns_dump_response(const pj_dns_parsed_response *res);
+PJ_DECL(void) pj_dns_dump_packet(const pj_dns_parsed_packet *res);
/**
diff --git a/pjlib-util/include/pjlib-util/errno.h b/pjlib-util/include/pjlib-util/errno.h
index 45e25f97..589fcb63 100644
--- a/pjlib-util/include/pjlib-util/errno.h
+++ b/pjlib-util/include/pjlib-util/errno.h
@@ -1,4 +1,4 @@
-/* $Id */
+/* $Id$ */
/*
* Copyright (C)2003-2006 Benny Prijono <benny@prijono.org>
*
@@ -107,34 +107,137 @@
***********************************************************/
/**
* @hideinitializer
- * Outgoing DNS query packet buffer is too small.
+ * DNS query packet buffer is too small.
* This error occurs when the user supplied buffer for creating DNS
* query (#pj_dns_make_query() function) is too small.
*/
#define PJLIB_UTIL_EDNSQRYTOOSMALL (PJLIB_UTIL_ERRNO_START+40) /* 320040 */
/**
* @hideinitializer
- * Invalid packet length in DNS response.
+ * Invalid DNS packet length.
* This error occurs when the received DNS response packet does not
* match all the fields length.
*/
#define PJLIB_UTIL_EDNSINSIZE (PJLIB_UTIL_ERRNO_START+41) /* 320041 */
/**
* @hideinitializer
- * Invalid class in DNS response.
+ * Invalid DNS class.
* This error occurs when the received DNS response contains network
* class other than IN (Internet).
*/
#define PJLIB_UTIL_EDNSINCLASS (PJLIB_UTIL_ERRNO_START+42) /* 320042 */
/**
* @hideinitializer
- * Invalid name pointer in DNS response.
+ * Invalid DNS name pointer.
* This error occurs when parsing the compressed names inside DNS
* response packet, when the name pointer points to an invalid address
* or the parsing has triggerred too much recursion.
*/
#define PJLIB_UTIL_EDNSINNAMEPTR (PJLIB_UTIL_ERRNO_START+43) /* 320043 */
+/**
+ * @hideinitializer
+ * Invalid DNS nameserver address. If hostname was specified for nameserver
+ * address, this error means that the function was unable to resolve
+ * the nameserver hostname.
+ */
+#define PJLIB_UTIL_EDNSINNSADDR (PJLIB_UTIL_ERRNO_START+44) /* 320044 */
+/**
+ * @hideinitializer
+ * No nameserver is in DNS resolver. No nameserver is configured in the
+ * resolver.
+ */
+#define PJLIB_UTIL_EDNSNONS (PJLIB_UTIL_ERRNO_START+45) /* 320045 */
+/**
+ * @hideinitializer
+ * No working DNS nameserver. All nameservers have been queried,
+ * but none was able to serve any DNS requests. These "bad" nameservers
+ * will be re-tested again for "goodness" after some period.
+ */
+#define PJLIB_UTIL_EDNSNOWORKINGNS (PJLIB_UTIL_ERRNO_START+46) /* 320046 */
+/**
+ * @hideinitializer
+ * No answer record in the DNS response.
+ */
+#define PJLIB_UTIL_EDNSNOANSWERREC (PJLIB_UTIL_ERRNO_START+47) /* 320047 */
+
+/* DNS ERRORS MAPPED FROM RCODE: */
+
+/**
+ * Start of error code mapped from DNS RCODE
+ */
+#define PJLIB_UTIL_DNS_RCODE_START (PJLIB_UTIL_ERRNO_START+50) /* 320050 */
+
+/**
+ * Map DNS RCODE status into pj_status_t.
+ */
+#define PJ_STATUS_FROM_DNS_RCODE(rcode) (rcode==0 ? PJ_SUCCESS : \
+ PJLIB_UTIL_DNS_RCODE_START+rcode)
+/**
+ * @hideinitializer
+ * Format error - The name server was unable to interpret the query.
+ * This corresponds to DNS RCODE 1.
+ */
+#define PJLIB_UTIL_EDNS_FORMERR PJ_STATUS_FROM_DNS_RCODE(1) /* 320051 */
+/**
+ * @hideinitializer
+ * Server failure - The name server was unable to process this query due to a
+ * problem with the name server.
+ * This corresponds to DNS RCODE 2.
+ */
+#define PJLIB_UTIL_EDNS_SERVFAIL PJ_STATUS_FROM_DNS_RCODE(2) /* 320052 */
+/**
+ * @hideinitializer
+ * Name Error - Meaningful only for responses from an authoritative name
+ * server, this code signifies that the domain name referenced in the query
+ * does not exist.
+ * This corresponds to DNS RCODE 3.
+ */
+#define PJLIB_UTIL_EDNS_NXDOMAIN PJ_STATUS_FROM_DNS_RCODE(3) /* 320053 */
+/**
+ * @hideinitializer
+ * Not Implemented - The name server does not support the requested kind of
+ * query.
+ * This corresponds to DNS RCODE 4.
+ */
+#define PJLIB_UTIL_EDNS_NOTIMPL PJ_STATUS_FROM_DNS_RCODE(4) /* 320054 */
+/**
+ * @hideinitializer
+ * Refused - The name server refuses to perform the specified operation for
+ * policy reasons.
+ * This corresponds to DNS RCODE 5.
+ */
+#define PJLIB_UTIL_EDNS_REFUSED PJ_STATUS_FROM_DNS_RCODE(5) /* 320055 */
+/**
+ * @hideinitializer
+ * The name exists.
+ * This corresponds to DNS RCODE 6.
+ */
+#define PJLIB_UTIL_EDNS_YXDOMAIN PJ_STATUS_FROM_DNS_RCODE(6) /* 320056 */
+/**
+ * @hideinitializer
+ * The RRset (name, type) exists.
+ * This corresponds to DNS RCODE 7.
+ */
+#define PJLIB_UTIL_EDNS_YXRRSET PJ_STATUS_FROM_DNS_RCODE(7) /* 320057 */
+/**
+ * @hideinitializer
+ * The RRset (name, type) does not exist.
+ * This corresponds to DNS RCODE 8.
+ */
+#define PJLIB_UTIL_EDNS_NXRRSET PJ_STATUS_FROM_DNS_RCODE(8) /* 320058 */
+/**
+ * @hideinitializer
+ * The requestor is not authorized to perform this operation.
+ * This corresponds to DNS RCODE 9.
+ */
+#define PJLIB_UTIL_EDNS_NOTAUTH PJ_STATUS_FROM_DNS_RCODE(9) /* 320059 */
+/**
+ * @hideinitializer
+ * The zone specified is not a zone.
+ * This corresponds to DNS RCODE 10.
+ */
+#define PJLIB_UTIL_EDNS_NOTZONE PJ_STATUS_FROM_DNS_RCODE(10)/* 320060 */
#endif /* __PJLIB_UTIL_ERRNO_H__ */
diff --git a/pjlib-util/include/pjlib-util/resolver.h b/pjlib-util/include/pjlib-util/resolver.h
new file mode 100644
index 00000000..471b5717
--- /dev/null
+++ b/pjlib-util/include/pjlib-util/resolver.h
@@ -0,0 +1,520 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2006 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 __PJLIB_UTIL_RESOLVER_H__
+#define __PJLIB_UTIL_RESOLVER_H__
+
+/**
+ * @file resolver.h
+ * @brief Asynchronous DNS resolver
+ */
+#include <pjlib-util/dns.h>
+
+
+PJ_BEGIN_DECL
+
+
+/**
+ * @defgroup PJ_DNS_RESOLVER Asynchronous DNS Server Resolution
+ * @ingroup PJLIB_UTIL
+ * @{
+ *
+ * This module manages the host/server resolution by performing asynchronous
+ * DNS queries and caching the results in the cache. It uses PJLIB-UTIL
+ * low-level DNS parsing functions (see @ref PJ_DNS) and currently supports
+ * several types of DNS resource records such as A record (typical query with
+ * gethostbyname()) and SRV record.
+ *
+ * \section PJ_DNS_RESOLVER_FEATURES Features
+ *
+ * \subsection PJ_DNS_RESOLVER_FEATURES_ASYNC Asynchronous Query and Query Aggregation
+ *
+ * The DNS queries are performed asychronously, with timeout setting
+ * configured on per resolver instance basis. Application can issue multiple
+ * asynchronous queries simultaneously. Subsequent queries to the same resource
+ * (name and DNS resource type) while existing query is still pending will be
+ * merged into one query, so that only one DNS request packet is issued.
+ *
+ * \subsection PJ_DNS_RESOLVER_FEATURES_RETRANSMISSION Query Retransmission
+ *
+ * Asynchronous query will be retransmitted if no response is received
+ * within the preconfigured time. Once maximum retransmission count is
+ * exceeded and no response is received, the query will time out and the
+ * callback will be called when error status.
+ *
+ * \subsection PJ_DNS_RESOLVER_FEATURES_CACHING Response Caching with TTL
+ *
+ * The resolver instance caches the results returned by nameservers, to
+ * enhance the performance by minimizing the message round-trip to the server.
+ * The TTL of the cached resposne is calculated from minimum TTL value found
+ * across all resource record (RR) TTL in the response and further more it can
+ * be limited to some preconfigured maximum TTL in the resolver.
+ *
+ * Response caching can be disabled by setting the maximum TTL value of the
+ * resolver to zero.
+ *
+ * \subsection PJ_DNS_RESOLVER_FEATURES_PARALLEL Parallel and Backup Name Servers
+ *
+ * When the resolver is configured with multiple nameservers, initially the
+ * queries will be issued to multiple name servers simultaneously to probe
+ * which servers are not active. Once the probing stage is done, subsequent
+ * queries will be directed to only one ACTIVE server which provides the best
+ * response time.
+ *
+ * Name servers are probed periodically to see which nameservers are active
+ * and which are down. This probing is done when a query is sent, thus no
+ * timer is needed to maintain this. Also probing will be done in parallel
+ * so that there would be no additional delay for the query.
+ *
+ *
+ * \subsection PJ_DNS_RESOLVER_FEATURES_REC Supported Resource Records
+ *
+ * The low-level DNS parsing utility (see @ref PJ_DNS) supports parsing of
+ * the following DNS resource records (RR):
+ * - DNS A record
+ * - DNS SRV record
+ * - DNS PTR record
+ * - DNS NS record
+ * - DNS CNAME record
+ *
+ * For other types of record, application can parse the raw resource
+ * record data (rdata) from the parsed DNS packet (#pj_dns_parsed_packet).
+ *
+ *
+ * \section PJ_DNS_RESOLVER_USING Using the Resolver
+ *
+ * To use the resolver, application first creates the resolver instance by
+ * calling #pj_dns_resolver_create(). If application already has its own
+ * timer and ioqueue instances, it can instruct the resolver to use these
+ * instances so that application does not need to poll the resolver
+ * periodically to process events. If application does not specify the
+ * timer and ioqueue instance for the resolver, an internal timer and
+ * ioqueue will be created by the resolver. And since the resolver does not
+ * create it's own thread, application MUST poll the resolver periodically
+ * by calling #pj_dns_resolver_handle_events() to allow events (network and
+ * timer) to be processed.
+ *
+ * Next, application MUST configure the nameservers to be used by the
+ * resolver, by calling #pj_dns_resolver_set_ns().
+ *
+ * Application performs asynchronous query by submitting the query with
+ * #pj_dns_resolver_start_query(). Once the query completes (either
+ * successfully or times out), the callback will be called.
+ *
+ * Application can cancel a pending query by calling #pj_dns_resolver_cancel_query().
+ *
+ * Resolver must be destroyed by calling #pj_dns_resolver_destroy() to
+ * release all resources back to the system.
+ *
+ *
+ * \section PJ_DNS_RESOLVER_LIMITATIONS Resolver Limitations
+ *
+ * Current implementation mainly suffers from a growing memory problem,
+ * which mainly is caused by the response caching. Although there is only
+ * one cache entry per {query, name} combination, these cache entry will
+ * never get deleted since there is no timer is created to invalidate these
+ * entries. So the more unique names being queried by application, there more
+ * enties will be created in the response cache.
+ *
+ * Note that a single response entry will occupy about 600-700 bytes of
+ * pool memory.
+ *
+ * Application can work around this problem by doing one of these:
+ * - disable caching by setting PJ_DNS_RESOLVER_MAX_TTL and
+ * PJ_DNS_RESOLVER_INVALID_TTL to zero.
+ * - periodically query #pj_dns_resolver_get_cached_count() and destroy-
+ * recreate the resolver to recycle the memory used by the resolver.
+ *
+ * Note that future improvement may solve this problem by introducing
+ * expiration timer to the cached entries.
+ *
+ *
+ * \section PJ_DNS_RESOLVER_REFERENCE Reference
+ *
+ * The PJLIB-UTIL resolver was built from the information in the following
+ * standards:
+ * - RFC 1035: "Domain names - implementation and specification"
+ * - RFC 2782: "A DNS RR for specifying the location of services (DNS SRV)"
+ */
+
+
+/*
+ * CONFIGURATIONS
+ */
+
+/**
+ * Maximum numbers of DNS nameservers that can be configured in resolver.
+ */
+#ifndef PJ_DNS_RESOLVER_MAX_NS
+# define PJ_DNS_RESOLVER_MAX_NS 16
+#endif
+
+
+/**
+ * Default retransmission delay, in miliseconds. The combination of
+ * retransmission delay and count determines the query timeout.
+ *
+ * Default: 2000 (2 seconds, according to RFC 1035)
+ */
+#ifndef PJ_DNS_RESOLVER_QUERY_RETRANSMIT_DELAY
+# define PJ_DNS_RESOLVER_QUERY_RETRANSMIT_DELAY 2000
+#endif
+
+
+/**
+ * Maximum number of transmissions before timeout is declared for
+ * the query.
+ *
+ * Default: 2
+ */
+#ifndef PJ_DNS_RESOLVER_QUERY_RETRANSMIT_COUNT
+# define PJ_DNS_RESOLVER_QUERY_RETRANSMIT_COUNT 5
+#endif
+
+
+/**
+ * Maximum life-time of DNS response in the resolver response cache,
+ * in seconds. If the value is zero, then DNS response caching will be
+ * disabled.
+ *
+ * Default is 300 seconds (5 minutes).
+ *
+ * @see PJ_DNS_RESOLVER_INVALID_TTL
+ */
+#ifndef PJ_DNS_RESOLVER_MAX_TTL
+# define PJ_DNS_RESOLVER_MAX_TTL (5*60)
+#endif
+
+/**
+ * The life-time of invalid DNS response in the resolver response cache.
+ * An invalid DNS response is a response without an answer. These
+ * responses can be put in the cache too to minimize message round-trip.
+ *
+ * Default: 0 (which means, invalid DNS response will not be cached).
+ *
+ * @see PJ_DNS_RESOLVER_MAX_TTL
+ */
+#ifndef PJ_DNS_RESOLVER_INVALID_TTL
+# define PJ_DNS_RESOLVER_INVALID_TTL 60
+#endif
+
+/**
+ * The interval on which nameservers which are known to be good to be
+ * probed again to determine whether they are still good. Note that
+ * this applies to both active nameserver (the one currently being used)
+ * and idle nameservers (good nameservers that are not currently selected).
+ * The probing to query the "goodness" of nameservers involves sending
+ * the same query to multiple servers, so it's probably not a good idea
+ * to send this probing too often.
+ *
+ * Default: 600 (ten minutes)
+ *
+ * @see PJ_DNS_RESOLVER_BAD_NS_TTL
+ */
+#ifndef PJ_DNS_RESOLVER_GOOD_NS_TTL
+# define PJ_DNS_RESOLVER_GOOD_NS_TTL (10*60)
+#endif
+
+/**
+ * The interval on which nameservers which known to be bad to be probed
+ * again to determine whether it is still bad.
+ *
+ * Default: 600 (ten minutes)
+ *
+ * @see PJ_DNS_RESOLVER_GOOD_NS_TTL
+ */
+#ifndef PJ_DNS_RESOLVER_BAD_NS_TTL
+# define PJ_DNS_RESOLVER_BAD_NS_TTL (1*60)
+#endif
+
+
+/**
+ * Maximum size of UDP packet. RFC 1035 states that maximum size of
+ * DNS packet carried over UDP is 512 bytes.
+ *
+ * Default: 512 byes
+ */
+#ifndef PJ_DNS_RESOLVER_MAX_UDP_SIZE
+# define PJ_DNS_RESOLVER_MAX_UDP_SIZE 512
+#endif
+
+
+/**
+ * Size of memory pool allocated for each individual DNS response cache.
+ * This value here should be more or less the same as maximum UDP packet
+ * size (PJ_DNS_RESOLVER_MAX_UDP_SIZE), since the DNS replicator function
+ * (#pj_dns_packet_dup()) is also capable of performing name compressions.
+ *
+ * Default: 512 (as a broad guidance, 400 is good for 4 SRV entries).
+ */
+#ifndef PJ_DNS_RESOLVER_RES_BUF_SIZE
+# define PJ_DNS_RESOLVER_RES_BUF_SIZE 512
+#endif
+
+
+
+/**
+ * Opaque data type for DNS resolver object.
+ */
+typedef struct pj_dns_resolver pj_dns_resolver;
+
+/**
+ * Opaque data type for asynchronous DNS query object.
+ */
+typedef struct pj_dns_async_query pj_dns_async_query;
+
+/**
+ * Type of asynchronous callback which will be called when the asynchronous
+ * query completes.
+ *
+ * @param user_data The user data set by application when creating the
+ * asynchronous query.
+ * @param status Status of the DNS resolution.
+ * @param response The response packet received from the server. This
+ * argument may be NULL when status is not PJ_SUCCESS.
+ */
+typedef void pj_dns_callback(void *user_data,
+ pj_status_t status,
+ pj_dns_parsed_packet *response);
+
+
+/**
+ * This structure describes resolver settings.
+ */
+typedef struct pj_dns_settings
+{
+ unsigned options; /**< Options flags. */
+ unsigned qretr_delay; /**< Query retransmit delay in msec. */
+ unsigned qretr_count; /**< Query maximum retransmission count. */
+ unsigned cache_max_ttl; /**< Maximum TTL for cached responses. If the
+ value is zero, caching is disabled. */
+} pj_dns_settings;
+
+
+/**
+ * Create DNS resolver instance. After the resolver is created, application
+ * MUST configure the nameservers with #pj_dns_resolver_set_ns().
+ *
+ * When creating the resolver, application may specify both timer heap
+ * and ioqueue instance, so that it doesn't need to poll the resolver
+ * periodically.
+ *
+ * @param pf Pool factory where the memory pool will be created from.
+ * @param name Optional resolver name to identify the instance in
+ * the log.
+ * @param options Optional options, must be zero for now.
+ * @param timer Optional timer heap instance to be used by the resolver.
+ * If timer heap is not specified, an internal timer will be
+ * created, and application would need to poll the resolver
+ * periodically.
+ * @param ioqueue Optional I/O Queue instance to be used by the resolver.
+ * If ioqueue is not specified, an internal one will be
+ * created, and application would need to poll the resolver
+ * periodically.
+ * @param p_resolver Pointer to receive the resolver instance.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code,
+ */
+PJ_DECL(pj_status_t) pj_dns_resolver_create(pj_pool_factory *pf,
+ const char *name,
+ unsigned options,
+ pj_timer_heap_t *timer,
+ pj_ioqueue_t *ioqueue,
+ pj_dns_resolver **p_resolver);
+
+
+/**
+ * Update the name servers for the DNS resolver. The name servers MUST be
+ * configured before any resolution can be done. The order of nameservers
+ * specifies their priority; the first name server will be tried first
+ * before the next in the list.
+ *
+ * @param resolver The resolver instance.
+ * @param count Number of name servers in the array.
+ * @param servers Array of name server IP addresses or hostnames. If
+ * hostname is specified, the hostname must be resolvable
+ * with pj_gethostbyname().
+ * @param ports Optional array of ports. If this argument is NULL,
+ * the nameserver will use default port.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code,
+ */
+PJ_DECL(pj_status_t) pj_dns_resolver_set_ns(pj_dns_resolver *resolver,
+ unsigned count,
+ const pj_str_t servers[],
+ const pj_uint16_t ports[]);
+
+
+/**
+ * Get the resolver current settings.
+ *
+ * @param resolver The resolver instance.
+ * @param st Buffer to be filled up with resolver settings.
+ *
+ * @return The query timeout setting, in seconds.
+ */
+PJ_DECL(pj_status_t) pj_dns_resolver_get_settings(pj_dns_resolver *resolver,
+ pj_dns_settings *st);
+
+
+/**
+ * Modify the resolver settings. Application should initialize the settings
+ * by retrieving current settings first before applying new settings, to
+ * ensure that all fields are initialized properly.
+ *
+ * @param resolver The resolver instance.
+ * @param st The resolver settings.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code,
+ */
+PJ_DECL(pj_status_t) pj_dns_resolver_set_settings(pj_dns_resolver *resolver,
+ const pj_dns_settings *st);
+
+
+/**
+ * Poll for events from the resolver. This function MUST be called
+ * periodically when the resolver is using it's own timer or ioqueue
+ * (in other words, when NULL is specified as either \a timer or
+ * \a ioqueue argument in #pj_dns_resolver_create()).
+ *
+ * @param resolver The resolver instance.
+ * @param timeout Maximum time to wait for event occurence. If this
+ * argument is NULL, this function will wait forever
+ * until events occur.
+ */
+PJ_DECL(void) pj_dns_resolver_handle_events(pj_dns_resolver *resolver,
+ const pj_time_val *timeout);
+
+
+/**
+ * Destroy DNS resolver instance.
+ *
+ * @param resolver The resolver object to be destryed
+ * @param notify If non-zero, all pending asynchronous queries will be
+ * cancelled and its callback will be called. If FALSE,
+ * then no callback will be called.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code,
+ */
+PJ_DECL(pj_status_t) pj_dns_resolver_destroy(pj_dns_resolver *resolver,
+ pj_bool_t notify);
+
+
+/**
+ * Create and start asynchronous DNS query for a single resource. Depending
+ * on whether response cache is available, this function will either start
+ * an asynchronous DNS query or call the callback immediately.
+ *
+ * If response is not available in the cache, an asynchronous query will be
+ * started, and callback will be called at some time later when the query
+ * completes. If \a p_query argument is not NULL, it will be filled with
+ * the asynchronous query object.
+ *
+ * If response is available in the cache, the callback will be called
+ * immediately before this function returns. In this case, if \a p_query
+ * argument is not NULL, the value will be set to NULL since no new query
+ * is started.
+ *
+ * @param resolver The resolver object.
+ * @param name The name to be resolved.
+ * @param type The type of resource (see #pj_dns_type constants).
+ * @param options Optional options, must be zero for now.
+ * @param cb Callback to be called when the query completes,
+ * either successfully or with failure.
+ * @param user_data Arbitrary user data to be associated with the query,
+ * and which will be given back in the callback.
+ * @param p_query Optional pointer to receive the query object, if one
+ * was started. If this pointer is specified, a NULL may
+ * be returned if response cache is available immediately.
+ *
+ * @return PJ_SUCCESS if either an asynchronous query has been
+ * started successfully or response cache is available and
+ * the user callback has been called.
+ */
+PJ_DECL(pj_status_t) pj_dns_resolver_start_query(pj_dns_resolver *resolver,
+ const pj_str_t *name,
+ int type,
+ unsigned options,
+ pj_dns_callback *cb,
+ void *user_data,
+ pj_dns_async_query **p_query);
+
+/**
+ * Cancel a pending query.
+ *
+ * @param query The pending asynchronous query to be cancelled.
+ * @param notify If non-zero, the callback will be called with failure
+ * status to notify that the query has been cancelled.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code,
+ */
+PJ_DECL(pj_status_t) pj_dns_resolver_cancel_query(pj_dns_async_query *query,
+ pj_bool_t notify);
+
+
+/**
+ * Put the specified DNS packet into DNS cache. This function is mainly used
+ * for testing the resolver, however it can also be used to inject entries
+ * into the resolver.
+ *
+ * The packet MUST contain either answer section or query section so that
+ * it can be indexed.
+ *
+ * @param resolver The resolver instance.
+ * @param pkt DNS packet to be added to the DNS cache. If the packet
+ * matches existing entry, it will update the entry.
+ * @param set_ttl If the value is PJ_FALSE, the entry will not expire
+ * (so use with care). Otherwise cache expiration will be
+ * calculated based on the TTL of the answeres.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_dns_resolver_add_entry(pj_dns_resolver *resolver,
+ const pj_dns_parsed_packet *pkt,
+ pj_bool_t set_ttl);
+
+/**
+ * Get the total number of response in the response cache.
+ *
+ * @param resolver The resolver instance.
+ *
+ * @return Current number of entries being stored in the response
+ * cache.
+ */
+PJ_DECL(unsigned) pj_dns_resolver_get_cached_count(pj_dns_resolver *resolver);
+
+
+/**
+ * Dump resolver state to the log.
+ *
+ * @param resolver The resolver instance.
+ * @param detail Will print detailed entries.
+ */
+PJ_DECL(void) pj_dns_resolver_dump(pj_dns_resolver *resolver,
+ pj_bool_t detail);
+
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+
+#endif /* __PJLIB_UTIL_RESOLVER_H__ */
+
diff --git a/pjlib-util/src/pjlib-util/dns.c b/pjlib-util/src/pjlib-util/dns.c
index 2afd6a22..e2d3b9f4 100644
--- a/pjlib-util/src/pjlib-util/dns.c
+++ b/pjlib-util/src/pjlib-util/dns.c
@@ -25,13 +25,29 @@
#include <pj/string.h>
+PJ_DEF(const char *) pj_dns_get_type_name(int type)
+{
+ switch (type) {
+ case PJ_DNS_TYPE_A: return "A";
+ case PJ_DNS_TYPE_SRV: return "SRV";
+ case PJ_DNS_TYPE_NS: return "NS";
+ case PJ_DNS_TYPE_CNAME: return "CNAME";
+ case PJ_DNS_TYPE_PTR: return "PTR";
+ case PJ_DNS_TYPE_MX: return "MX";
+ case PJ_DNS_TYPE_TXT: return "TXT";
+ case PJ_DNS_TYPE_NAPTR: return "NAPTR";
+ }
+ return "(Unknown)";
+}
+
+
/**
* Initialize a DNS query transaction.
*/
PJ_DEF(pj_status_t) pj_dns_make_query( void *packet,
unsigned *size,
pj_uint16_t id,
- pj_dns_type qtype,
+ int qtype,
const pj_str_t *name)
{
pj_dns_hdr *hdr;
@@ -224,17 +240,42 @@ static pj_status_t get_name(int rec_counter, const char *pkt,
/* Skip query records. */
-static pj_status_t skip_query(const char *pkt, const char *start,
- const char *max, int *skip_len)
+static pj_status_t parse_query(pj_dns_parsed_query *q, pj_pool_t *pool,
+ const char *pkt, const char *start,
+ const char *max, int *parsed_len)
{
- int name_len = 0;
+ const char *p = start;
+ int name_len, name_part_len;
pj_status_t status;
- status = get_name_len(0, pkt, start, max, skip_len, &name_len);
+ /* Get the length of the name */
+ status = get_name_len(0, pkt, start, max, &name_part_len, &name_len);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Allocate memory for the name */
+ q->name.ptr = pj_pool_alloc(pool, name_len+4);
+ q->name.slen = 0;
+
+ /* Get the name */
+ status = get_name(0, pkt, start, max, &q->name);
if (status != PJ_SUCCESS)
return status;
- (*skip_len) += 4;
+ p = (start + name_part_len);
+
+ /* Get the type */
+ pj_memcpy(&q->type, p, 2);
+ q->type = pj_ntohs(q->type);
+ p += 2;
+
+ /* Get the class */
+ pj_memcpy(&q->dnsclass, p, 2);
+ q->dnsclass = pj_ntohs(q->dnsclass);
+ p += 2;
+
+ *parsed_len = (int)(p - start);
+
return PJ_SUCCESS;
}
@@ -275,12 +316,12 @@ static pj_status_t parse_rr(pj_dns_parsed_rr *rr, pj_pool_t *pool,
p += 2;
/* Get the class */
- pj_memcpy(&rr->class_, p, 2);
- rr->class_ = pj_ntohs(rr->class_);
+ pj_memcpy(&rr->dnsclass, p, 2);
+ rr->dnsclass = pj_ntohs(rr->dnsclass);
p += 2;
/* Class MUST be IN */
- if (rr->class_ != 1)
+ if (rr->dnsclass != 1)
return PJLIB_UTIL_EDNSINCLASS;
/* Get TTL */
@@ -297,10 +338,6 @@ static pj_status_t parse_rr(pj_dns_parsed_rr *rr, pj_pool_t *pool,
if (p + rr->rdlength > max)
return PJLIB_UTIL_EDNSINSIZE;
- /* Copy the raw data */
- rr->data = pj_pool_alloc(pool, rr->rdlength);
- pj_memcpy(rr->data, p, rr->rdlength);
-
/* Parse some well known records */
if (rr->type == PJ_DNS_TYPE_A) {
pj_in_addr ip_addr;
@@ -364,6 +401,10 @@ static pj_status_t parse_rr(pj_dns_parsed_rr *rr, pj_pool_t *pool,
p += name_part_len;
} else {
+ /* Copy the raw data */
+ rr->data = pj_pool_alloc(pool, rr->rdlength);
+ pj_memcpy(rr->data, p, rr->rdlength);
+
p += rr->rdlength;
}
@@ -373,14 +414,14 @@ static pj_status_t parse_rr(pj_dns_parsed_rr *rr, pj_pool_t *pool,
/*
- * Parse raw DNS response packet into DNS response structure.
+ * Parse raw DNS packet into DNS packet structure.
*/
-PJ_DEF(pj_status_t) pj_dns_parse_response( pj_pool_t *pool,
- const void *packet,
- unsigned size,
- pj_dns_parsed_response **p_res)
+PJ_DEF(pj_status_t) pj_dns_parse_packet( pj_pool_t *pool,
+ const void *packet,
+ unsigned size,
+ pj_dns_parsed_packet **p_res)
{
- pj_dns_parsed_response *res;
+ pj_dns_parsed_packet *res;
char *start, *end;
pj_status_t status;
unsigned i;
@@ -392,8 +433,8 @@ PJ_DEF(pj_status_t) pj_dns_parse_response( pj_pool_t *pool,
if (size < sizeof(pj_dns_hdr))
return PJLIB_UTIL_EDNSINSIZE;
- /* Create the response */
- res = pj_pool_zalloc(pool, sizeof(pj_dns_parsed_response));
+ /* Create the structure */
+ res = pj_pool_zalloc(pool, sizeof(pj_dns_parsed_packet));
/* Copy the DNS header, and convert endianness to host byte order */
pj_memcpy(&res->hdr, packet, sizeof(pj_dns_hdr));
@@ -408,17 +449,21 @@ PJ_DEF(pj_status_t) pj_dns_parse_response( pj_pool_t *pool,
start = ((char*)packet) + sizeof(pj_dns_hdr);
end = ((char*)packet) + size;
- /* If we have query records (some DNS servers do send them), skip
- * the records.
+ /* Parse query records (if any).
*/
- for (i=0; i<res->hdr.qdcount; ++i) {
- int skip_len;
-
- status = skip_query(packet, start, end, &skip_len);
- if (status != PJ_SUCCESS)
- return status;
+ if (res->hdr.qdcount) {
+ res->q = pj_pool_zalloc(pool, res->hdr.qdcount *
+ sizeof(pj_dns_parsed_query));
+ for (i=0; i<res->hdr.qdcount; ++i) {
+ int parsed_len;
+
+ status = parse_query(&res->q[i], pool, packet, start, end,
+ &parsed_len);
+ if (status != PJ_SUCCESS)
+ return status;
- start += skip_len;
+ start += parsed_len;
+ }
}
/* Parse answer, if any */
@@ -477,3 +522,155 @@ PJ_DEF(pj_status_t) pj_dns_parse_response( pj_pool_t *pool,
return PJ_SUCCESS;
}
+
+
+/* Perform name compression scheme.
+ * If a name is already in the nametable, when no need to duplicate
+ * the string with the pool, but rather just use the pointer there.
+ */
+static void apply_name_table( unsigned *count,
+ pj_str_t nametable[],
+ const pj_str_t *src,
+ pj_pool_t *pool,
+ pj_str_t *dst)
+{
+ unsigned i;
+
+ /* Scan strings in nametable */
+ for (i=0; i<*count; ++i) {
+ if (pj_stricmp(&nametable[i], src) == 0)
+ break;
+ }
+
+ /* If name is found in nametable, use the pointer in the nametable */
+ if (i != *count) {
+ dst->ptr = nametable[i].ptr;
+ dst->slen = nametable[i].slen;
+ return;
+ }
+
+ /* Otherwise duplicate the string, and insert new name in nametable */
+ pj_strdup(pool, dst, src);
+
+ if (*count < PJ_DNS_MAX_NAMES_IN_NAMETABLE) {
+ nametable[*count].ptr = dst->ptr;
+ nametable[*count].slen = dst->slen;
+
+ ++(*count);
+ }
+}
+
+static void copy_query(pj_pool_t *pool, pj_dns_parsed_query *dst,
+ const pj_dns_parsed_query *src,
+ unsigned *nametable_count,
+ pj_str_t nametable[])
+{
+ pj_memcpy(dst, src, sizeof(*src));
+ apply_name_table(nametable_count, nametable, &src->name, pool, &dst->name);
+}
+
+
+static void copy_rr(pj_pool_t *pool, pj_dns_parsed_rr *dst,
+ const pj_dns_parsed_rr *src,
+ unsigned *nametable_count,
+ pj_str_t nametable[])
+{
+ pj_memcpy(dst, src, sizeof(*src));
+ apply_name_table(nametable_count, nametable, &src->name, pool, &dst->name);
+
+ if (src->data) {
+ dst->data = pj_pool_alloc(pool, src->rdlength);
+ pj_memcpy(dst->data, src->data, src->rdlength);
+ }
+
+ if (src->type == PJ_DNS_TYPE_SRV) {
+ apply_name_table(nametable_count, nametable, &src->rdata.srv.target,
+ pool, &dst->rdata.srv.target);
+ } else if (src->type == PJ_DNS_TYPE_A) {
+ pj_strdup(pool, &dst->rdata.a.ip_addr, &src->rdata.a.ip_addr);
+ } else if (src->type == PJ_DNS_TYPE_CNAME) {
+ pj_strdup(pool, &dst->rdata.cname.name, &src->rdata.cname.name);
+ } else if (src->type == PJ_DNS_TYPE_NS) {
+ pj_strdup(pool, &dst->rdata.ns.name, &src->rdata.ns.name);
+ } else if (src->type == PJ_DNS_TYPE_PTR) {
+ pj_strdup(pool, &dst->rdata.ptr.name, &src->rdata.ptr.name);
+ }
+}
+
+/*
+ * Duplicate DNS packet.
+ */
+PJ_DEF(void) pj_dns_packet_dup(pj_pool_t *pool,
+ const pj_dns_parsed_packet*p,
+ pj_dns_parsed_packet **p_dst)
+{
+ pj_dns_parsed_packet *dst;
+ unsigned nametable_count = 0;
+#if PJ_DNS_MAX_NAMES_IN_NAMETABLE
+ pj_str_t nametable[PJ_DNS_MAX_NAMES_IN_NAMETABLE];
+#else
+ pj_str_t *nametable = NULL;
+#endif
+ unsigned i;
+
+ PJ_ASSERT_ON_FAIL(pool && p && p_dst, return);
+
+ /* Create packet and copy header */
+ *p_dst = dst = pj_pool_zalloc(pool, sizeof(pj_dns_parsed_packet));
+ pj_memcpy(&dst->hdr, &p->hdr, sizeof(p->hdr));
+
+ /* Initialize section counts in the target packet to zero.
+ * If memory allocation fails during copying process, the target packet
+ * should have a correct section counts.
+ */
+ dst->hdr.qdcount = 0;
+ dst->hdr.anscount = 0;
+ dst->hdr.nscount = 0;
+ dst->hdr.arcount = 0;
+
+
+ /* Copy query section */
+ if (p->hdr.qdcount) {
+ dst->q = pj_pool_alloc(pool, p->hdr.qdcount *
+ sizeof(pj_dns_parsed_query));
+ for (i=0; i<p->hdr.qdcount; ++i) {
+ copy_query(pool, &dst->q[i], &p->q[i],
+ &nametable_count, nametable);
+ ++dst->hdr.qdcount;
+ }
+ }
+
+ /* Copy answer section */
+ if (p->hdr.anscount) {
+ dst->ans = pj_pool_alloc(pool, p->hdr.anscount *
+ sizeof(pj_dns_parsed_rr));
+ for (i=0; i<p->hdr.anscount; ++i) {
+ copy_rr(pool, &dst->ans[i], &p->ans[i],
+ &nametable_count, nametable);
+ ++dst->hdr.anscount;
+ }
+ }
+
+ /* Copy NS section */
+ if (p->hdr.nscount) {
+ dst->ns = pj_pool_alloc(pool, p->hdr.nscount *
+ sizeof(pj_dns_parsed_rr));
+ for (i=0; i<p->hdr.nscount; ++i) {
+ copy_rr(pool, &dst->ns[i], &p->ns[i],
+ &nametable_count, nametable);
+ ++dst->hdr.nscount;
+ }
+ }
+
+ /* Copy additional info section */
+ if (p->hdr.arcount) {
+ dst->arr = pj_pool_alloc(pool, p->hdr.arcount *
+ sizeof(pj_dns_parsed_rr));
+ for (i=0; i<p->hdr.arcount; ++i) {
+ copy_rr(pool, &dst->arr[i], &p->arr[i],
+ &nametable_count, nametable);
+ ++dst->hdr.arcount;
+ }
+ }
+}
+
diff --git a/pjlib-util/src/pjlib-util/dns_dump.c b/pjlib-util/src/pjlib-util/dns_dump.c
index 37738c96..31602163 100644
--- a/pjlib-util/src/pjlib-util/dns_dump.c
+++ b/pjlib-util/src/pjlib-util/dns_dump.c
@@ -19,43 +19,93 @@
#include <pjlib-util/dns.h>
#include <pj/assert.h>
#include <pj/log.h>
+#include <pj/string.h>
#define THIS_FILE "dns_dump.c"
#define LEVEL 3
-static const char *get_rr_name(int type)
+static const char *spell_ttl(char *buf, int size, unsigned ttl)
{
- switch (type) {
- case PJ_DNS_TYPE_A: return "A";
- case PJ_DNS_TYPE_NS: return "NS";
- case PJ_DNS_TYPE_CNAME: return "CNAME";
- case PJ_DNS_TYPE_PTR: return "PTR";
- case PJ_DNS_TYPE_MX: return "MX";
- case PJ_DNS_TYPE_TXT: return "TXT";
- case PJ_DNS_TYPE_SRV: return "SRV";
- case PJ_DNS_TYPE_NAPTR: return "NAPTR";
+#define DAY (3600*24)
+#define HOUR (3600)
+#define MINUTE (60)
+
+ char *p = buf;
+ int len;
+
+ if (ttl > DAY) {
+ len = pj_ansi_snprintf(p, size, "%dd ", ttl/DAY);
+ if (len < 1)
+ return "-err-";
+ size -= len;
+ p += len;
+ ttl %= DAY;
}
- return "(Unknown)";
+
+ if (ttl > HOUR) {
+ len = pj_ansi_snprintf(p, size, "%dh ", ttl/HOUR);
+ if (len < 1)
+ return "-err-";
+ size -= len;
+ p += len;
+ ttl %= HOUR;
+ }
+
+ if (ttl > MINUTE) {
+ len = pj_ansi_snprintf(p, size, "%dm ", ttl/MINUTE);
+ if (len < 1)
+ return "-err-";
+ size -= len;
+ p += len;
+ ttl %= MINUTE;
+ }
+
+ if (ttl > 0) {
+ len = pj_ansi_snprintf(p, size, "%ds ", ttl);
+ if (len < 1)
+ return "-err-";
+ size -= len;
+ p += len;
+ ttl = 0;
+ }
+
+ *p = '\0';
+ return buf;
+}
+
+
+static void dump_query(unsigned index, const pj_dns_parsed_query *q)
+{
+ PJ_LOG(3,(THIS_FILE, " %d. Name: %.*s",
+ index, (int)q->name.slen, q->name.ptr));
+ PJ_LOG(3,(THIS_FILE, " Type: %s (%d)",
+ pj_dns_get_type_name(q->type), q->type));
+ PJ_LOG(3,(THIS_FILE, " Class: %s (%d)",
+ (q->dnsclass==1 ? "IN" : "<Unknown>"), q->dnsclass));
}
static void dump_answer(unsigned index, const pj_dns_parsed_rr *rr)
{
const pj_str_t root_name = { "<Root>", 6 };
const pj_str_t *name = &rr->name;
+ char ttl_words[32];
if (name->slen == 0)
name = &root_name;
- PJ_LOG(3,(THIS_FILE, " %d. %s record (type=%d)", index, get_rr_name(rr->type),
+ PJ_LOG(3,(THIS_FILE, " %d. %s record (type=%d)",
+ index, pj_dns_get_type_name(rr->type),
rr->type));
PJ_LOG(3,(THIS_FILE, " Name: %.*s", (int)name->slen, name->ptr));
- PJ_LOG(3,(THIS_FILE, " TTL: %u", rr->ttl));
+ PJ_LOG(3,(THIS_FILE, " TTL: %u (%s)", rr->ttl,
+ spell_ttl(ttl_words, sizeof(ttl_words), rr->ttl)));
PJ_LOG(3,(THIS_FILE, " Data length: %u", rr->rdlength));
if (rr->type == PJ_DNS_TYPE_SRV) {
PJ_LOG(3,(THIS_FILE, " SRV: prio=%d, weight=%d %.*s:%d",
rr->rdata.srv.prio, rr->rdata.srv.weight,
- (int)rr->rdata.srv.target.slen, rr->rdata.srv.target.ptr,
+ (int)rr->rdata.srv.target.slen,
+ rr->rdata.srv.target.ptr,
rr->rdata.srv.port));
} else if (rr->type == PJ_DNS_TYPE_CNAME ||
rr->type == PJ_DNS_TYPE_NS ||
@@ -72,7 +122,7 @@ static void dump_answer(unsigned index, const pj_dns_parsed_rr *rr)
}
-PJ_DEF(void) pj_dns_dump_response(const pj_dns_parsed_response *res)
+PJ_DEF(void) pj_dns_dump_packet(const pj_dns_parsed_packet *res)
{
unsigned i;
@@ -82,18 +132,28 @@ PJ_DEF(void) pj_dns_dump_response(const pj_dns_parsed_response *res)
PJ_LOG(3,(THIS_FILE, "Domain Name System packet (%s):",
(PJ_DNS_GET_QR(res->hdr.flags) ? "response" : "query")));
PJ_LOG(3,(THIS_FILE, " Transaction ID: %d", res->hdr.id));
- PJ_LOG(3,(THIS_FILE, " Flags: type=%s, opcode=%d, authoritative=%d, truncated=%d, rcode=%d",
- (PJ_DNS_GET_QR(res->hdr.flags) ? "response" : "query"),
+ PJ_LOG(3,(THIS_FILE,
+ " Flags: opcode=%d, authoritative=%d, truncated=%d, rcode=%d",
PJ_DNS_GET_OPCODE(res->hdr.flags),
PJ_DNS_GET_AA(res->hdr.flags),
PJ_DNS_GET_TC(res->hdr.flags),
PJ_DNS_GET_RCODE(res->hdr.flags)));
- PJ_LOG(3,(THIS_FILE, " Nb of question RR: %d", res->hdr.qdcount));
+ PJ_LOG(3,(THIS_FILE, " Nb of queries: %d", res->hdr.qdcount));
PJ_LOG(3,(THIS_FILE, " Nb of answer RR: %d", res->hdr.anscount));
PJ_LOG(3,(THIS_FILE, " Nb of authority RR: %d", res->hdr.nscount));
PJ_LOG(3,(THIS_FILE, " Nb of additional RR: %d", res->hdr.arcount));
PJ_LOG(3,(THIS_FILE, ""));
+ /* Dump queries */
+ if (res->hdr.qdcount) {
+ PJ_LOG(3,(THIS_FILE, " Queries:"));
+
+ for (i=0; i<res->hdr.qdcount; ++i) {
+ dump_query(i, &res->q[i]);
+ }
+ PJ_LOG(3,(THIS_FILE, ""));
+ }
+
/* Dump answers */
if (res->hdr.anscount) {
PJ_LOG(3,(THIS_FILE, " Answers RR:"));
diff --git a/pjlib-util/src/pjlib-util/errno.c b/pjlib-util/src/pjlib-util/errno.c
index 4bb652aa..2da114f4 100644
--- a/pjlib-util/src/pjlib-util/errno.c
+++ b/pjlib-util/src/pjlib-util/errno.c
@@ -49,10 +49,25 @@ static const struct
PJ_BUILD_ERR( PJLIB_UTIL_EINXML, "Invalid XML message" ),
/* DNS errors */
- PJ_BUILD_ERR( PJLIB_UTIL_EDNSQRYTOOSMALL, "Outgoing DNS query packet buffer is too small"),
- PJ_BUILD_ERR( PJLIB_UTIL_EDNSINSIZE, "Invalid packet length in DNS response"),
- PJ_BUILD_ERR( PJLIB_UTIL_EDNSINCLASS, "Invalid class in DNS response"),
- PJ_BUILD_ERR( PJLIB_UTIL_EDNSINNAMEPTR, "Invalid name pointer in DNS response"),
+ PJ_BUILD_ERR( PJLIB_UTIL_EDNSQRYTOOSMALL, "DNS query packet buffer is too small"),
+ PJ_BUILD_ERR( PJLIB_UTIL_EDNSINSIZE, "Invalid DNS packet length"),
+ PJ_BUILD_ERR( PJLIB_UTIL_EDNSINCLASS, "Invalid DNS class"),
+ PJ_BUILD_ERR( PJLIB_UTIL_EDNSINNAMEPTR, "Invalid DNS name pointer"),
+ PJ_BUILD_ERR( PJLIB_UTIL_EDNSINNSADDR, "Invalid DNS nameserver address"),
+ PJ_BUILD_ERR( PJLIB_UTIL_EDNSNONS, "No nameserver is in DNS resolver"),
+ PJ_BUILD_ERR( PJLIB_UTIL_EDNSNOWORKINGNS, "No working DNS nameserver"),
+ PJ_BUILD_ERR( PJLIB_UTIL_EDNSNOANSWERREC, "No answer record in the DNS response"),
+
+ PJ_BUILD_ERR( PJLIB_UTIL_EDNS_FORMERR, "DNS \"Format error\""),
+ PJ_BUILD_ERR( PJLIB_UTIL_EDNS_SERVFAIL, "DNS \"Server failure\""),
+ PJ_BUILD_ERR( PJLIB_UTIL_EDNS_NXDOMAIN, "DNS \"Name Error\""),
+ PJ_BUILD_ERR( PJLIB_UTIL_EDNS_NOTIMPL, "DNS \"Not Implemented\""),
+ PJ_BUILD_ERR( PJLIB_UTIL_EDNS_REFUSED, "DNS \"Refused\""),
+ PJ_BUILD_ERR( PJLIB_UTIL_EDNS_YXDOMAIN, "DNS \"The name exists\""),
+ PJ_BUILD_ERR( PJLIB_UTIL_EDNS_YXRRSET, "DNS \"The RRset (name, type) exists\""),
+ PJ_BUILD_ERR( PJLIB_UTIL_EDNS_NXRRSET, "DNS \"The RRset (name, type) does not exist\""),
+ PJ_BUILD_ERR( PJLIB_UTIL_EDNS_NOTAUTH, "DNS \"Not authorized\""),
+ PJ_BUILD_ERR( PJLIB_UTIL_EDNS_NOTZONE, "DNS \"The zone specified is not a zone\""),
};
#endif /* PJ_HAS_ERROR_STRING */
diff --git a/pjlib-util/src/pjlib-util/resolver.c b/pjlib-util/src/pjlib-util/resolver.c
new file mode 100644
index 00000000..3694c8e1
--- /dev/null
+++ b/pjlib-util/src/pjlib-util/resolver.c
@@ -0,0 +1,1408 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2006 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 <pjlib-util/resolver.h>
+#include <pjlib-util/errno.h>
+#include <pj/assert.h>
+#include <pj/ctype.h>
+#include <pj/except.h>
+#include <pj/hash.h>
+#include <pj/ioqueue.h>
+#include <pj/log.h>
+#include <pj/os.h>
+#include <pj/pool.h>
+#include <pj/pool_buf.h>
+#include <pj/string.h>
+#include <pj/sock.h>
+#include <pj/timer.h>
+
+
+#define THIS_FILE "resolver.c"
+
+
+/* Check that maximum DNS nameservers is not too large.
+ * This has got todo with the datatype to index the nameserver in the query.
+ */
+#if PJ_DNS_RESOLVER_MAX_NS > 256
+# error "PJ_DNS_RESOLVER_MAX_NS is too large (max=256)"
+#endif
+
+
+#define RES_HASH_TABLE_SIZE 127 /**< Hash table size (must be 2^n-1 */
+#define PORT 53 /**< Default NS port. */
+#define Q_HASH_TABLE_SIZE 127 /**< Query hash table size */
+#define TIMER_SIZE 127 /**< Initial number of timers. */
+#define MAX_FD 3 /**< Maximum internal sockets. */
+
+#define RES_BUF_SZ PJ_DNS_RESOLVER_RES_BUF_SIZE
+#define UDPSZ PJ_DNS_RESOLVER_MAX_UDP_SIZE
+
+
+/* Nameserver state */
+enum ns_state
+{
+ STATE_PROBING,
+ STATE_ACTIVE,
+ STATE_BAD,
+};
+
+/*
+ * Each nameserver entry.
+ * A name server is identified by its socket address (IP and port).
+ * Each NS will have a flag to indicate whether it's properly functioning.
+ */
+struct nameserver
+{
+ pj_sockaddr_in addr; /**< Server address. */
+
+ enum ns_state state; /**< Nameserver state. */
+ pj_time_val state_expiry; /**< Time set next state. */
+ pj_time_val rt_delay; /**< Response time. */
+
+
+ /* For calculating rt_delay: */
+ pj_uint16_t q_id; /**< Query ID. */
+ pj_time_val sent_time; /**< Time this query is sent. */
+};
+
+
+/* Child query list head
+ * See comments on pj_dns_async_query below.
+ */
+struct query_head
+{
+ PJ_DECL_LIST_MEMBER(pj_dns_async_query);
+};
+
+
+/* Key to look for outstanding query and/or cached response */
+struct res_key
+{
+ pj_uint16_t qtype; /**< Query type. */
+ char name[PJ_MAX_HOSTNAME]; /**< Name being queried */
+};
+
+
+/*
+ * This represents each asynchronous query entry.
+ * This entry will be put in two hash tables, the first one keyed on the DNS
+ * transaction ID to match response with the query, and the second one keyed
+ * on "res_key" structure above to match a new request against outstanding
+ * requests.
+ *
+ * An asynchronous entry may have child entries; child entries are subsequent
+ * queries to the same resource while there is pending query on the same
+ * DNS resource name and type. When a query has child entries, once the
+ * response is received (or error occurs), the response will trigger callback
+ * invocations for all childs entries.
+ *
+ * Note: when application cancels the query, the callback member will be
+ * set to NULL, but for simplicity, the query will be let running.
+ */
+struct pj_dns_async_query
+{
+ PJ_DECL_LIST_MEMBER(pj_dns_async_query); /**< List member. */
+
+ pj_dns_resolver *resolver; /**< The resolver instance. */
+ pj_uint16_t id; /**< Transaction ID. */
+
+ unsigned transmit_cnt; /**< Number of transmissions. */
+
+ struct res_key key; /**< Key to index this query. */
+ char hbufid[PJ_HASH_ENTRY_SIZE]; /**< Hash buffer 1 */
+ char hbufkey[PJ_HASH_ENTRY_SIZE]; /**< Hash buffer 2 */
+ pj_timer_entry timer_entry; /**< Timer to manage timeouts */
+ unsigned options; /**< Query options. */
+ void *user_data; /**< Application data. */
+ pj_dns_callback *cb; /**< Callback to be called. */
+ struct query_head child_head; /**< Child queries list head. */
+};
+
+
+/* This structure is used to keep cached response entry.
+ * The cache is a hash table keyed on "res_key" structure above.
+ */
+struct cached_res
+{
+ PJ_DECL_LIST_MEMBER(struct cached_res);
+
+ struct res_key key; /**< Resource key. */
+ char buf[RES_BUF_SZ];/**< Resource buffer. */
+ char hbuf[PJ_HASH_ENTRY_SIZE]; /**< Hash buffer */
+ pj_time_val expiry_time; /**< Expiration time. */
+ pj_dns_parsed_packet *pkt; /**< The response packet. */
+};
+
+
+/* Resolver entry */
+struct pj_dns_resolver
+{
+ pj_str_t name; /**< Resolver instance name for id. */
+
+ /* Internals */
+ pj_pool_t *pool; /**< Internal pool. */
+ pj_mutex_t *mutex; /**< Mutex protection. */
+ pj_bool_t own_timer; /**< Do we own timer? */
+ pj_timer_heap_t *timer; /**< Timer instance. */
+ pj_bool_t own_ioqueue; /**< Do we own ioqueue? */
+ pj_ioqueue_t *ioqueue; /**< Ioqueue instance. */
+ char tmp_pool[1500];/**< Temporary pool buffer. */
+
+ /* Socket */
+ pj_sock_t udp_sock; /**< UDP socket. */
+ pj_ioqueue_key_t *udp_key; /**< UDP socket ioqueue key. */
+ unsigned char udp_rx_pkt[UDPSZ];/**< UDP receive buffer. */
+ unsigned char udp_tx_pkt[UDPSZ];/**< UDP receive buffer. */
+ pj_ssize_t udp_len; /**< Length of received packet. */
+ pj_ioqueue_op_key_t udp_op_key; /**< UDP read operation key. */
+ pj_sockaddr_in udp_src_addr; /**< Source address of packet */
+ int udp_addr_len; /**< Source address length. */
+
+ /* Settings */
+ pj_dns_settings settings; /**< Resolver settings. */
+
+ /* Nameservers */
+ unsigned ns_count; /**< Number of name servers. */
+ struct nameserver ns[PJ_DNS_RESOLVER_MAX_NS]; /**< Array of NS. */
+
+ /* Last DNS transaction ID used. */
+ pj_uint16_t last_id;
+
+ /* Hash table for cached response */
+ pj_hash_table_t *hrescache; /**< Cached response in hash table */
+
+ /* Cached response free list */
+ struct cached_res res_free_nodes;
+
+ /* Pending asynchronous query, hashed by transaction ID. */
+ pj_hash_table_t *hquerybyid;
+
+ /* Pending asynchronous query, hashed by "res_key" */
+ pj_hash_table_t *hquerybyres;
+
+ /* Query entries free list */
+ struct query_head query_free_nodes;
+};
+
+
+/* Callback from ioqueue when packet is received */
+static void on_read_complete(pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_ssize_t bytes_read);
+
+/* Callback to be called when query has timed out */
+static void on_timeout( pj_timer_heap_t *timer_heap,
+ struct pj_timer_entry *entry);
+
+/* Select which nameserver to use */
+static pj_status_t select_nameservers(pj_dns_resolver *resolver,
+ unsigned *count,
+ unsigned servers[]);
+
+
+/*
+ * Create the resolver.
+ */
+PJ_DEF(pj_status_t) pj_dns_resolver_create( pj_pool_factory *pf,
+ const char *name,
+ unsigned options,
+ pj_timer_heap_t *timer,
+ pj_ioqueue_t *ioqueue,
+ pj_dns_resolver **p_resolver)
+{
+ pj_pool_t *pool;
+ pj_dns_resolver *resv;
+ pj_ioqueue_callback socket_cb;
+ pj_status_t status;
+
+ /* Sanity check */
+ PJ_ASSERT_RETURN(pf && p_resolver, PJ_EINVAL);
+
+ if (name == NULL)
+ name = THIS_FILE;
+
+ /* Create and initialize resolver instance */
+ pool = pj_pool_create(pf, name, 4000, 4000, NULL);
+ if (!pool)
+ return PJ_ENOMEM;
+
+ /* Create pool and name */
+ resv = pj_pool_zalloc(pool, sizeof(struct pj_dns_resolver));
+ resv->pool = pool;
+ resv->udp_sock = PJ_INVALID_SOCKET;
+ pj_strdup2_with_null(pool, &resv->name, name);
+
+ /* Create the mutex */
+ status = pj_mutex_create_recursive(pool, name, &resv->mutex);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Timer, ioqueue, and settings */
+ resv->timer = timer;
+ resv->ioqueue = ioqueue;
+ resv->last_id = 1;
+ resv->settings.options = options;
+ resv->settings.qretr_delay = PJ_DNS_RESOLVER_QUERY_RETRANSMIT_DELAY;
+ resv->settings.qretr_count = PJ_DNS_RESOLVER_QUERY_RETRANSMIT_COUNT;
+ resv->settings.cache_max_ttl = PJ_DNS_RESOLVER_MAX_TTL;
+
+ /* Create the timer heap if one is not specified */
+ if (resv->timer == NULL) {
+ status = pj_timer_heap_create(pool, TIMER_SIZE, &resv->timer);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+ }
+
+ /* Create the ioqueue if one is not specified */
+ if (resv->ioqueue == NULL) {
+ status = pj_ioqueue_create(pool, MAX_FD, &resv->ioqueue);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+ }
+
+ /* Response cache hash table and item list */
+ resv->hrescache = pj_hash_create(pool, RES_HASH_TABLE_SIZE);
+ pj_list_init(&resv->res_free_nodes);
+
+ /* Query hash table and free list. */
+ resv->hquerybyid = pj_hash_create(pool, Q_HASH_TABLE_SIZE);
+ resv->hquerybyres = pj_hash_create(pool, Q_HASH_TABLE_SIZE);
+ pj_list_init(&resv->query_free_nodes);
+
+ /* Create the UDP socket */
+ status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &resv->udp_sock);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Register to ioqueue */
+ pj_bzero(&socket_cb, sizeof(socket_cb));
+ socket_cb.on_read_complete = &on_read_complete;
+ status = pj_ioqueue_register_sock(pool, resv->ioqueue, resv->udp_sock,
+ resv, &socket_cb, &resv->udp_key);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ pj_ioqueue_op_key_init(&resv->udp_op_key, sizeof(resv->udp_op_key));
+
+ /* Start asynchronous read to the UDP socket */
+ resv->udp_len = sizeof(resv->udp_rx_pkt);
+ resv->udp_addr_len = sizeof(resv->udp_src_addr);
+ status = pj_ioqueue_recvfrom(resv->udp_key, &resv->udp_op_key,
+ resv->udp_rx_pkt, &resv->udp_len,
+ PJ_IOQUEUE_ALWAYS_ASYNC,
+ &resv->udp_src_addr, &resv->udp_addr_len);
+ if (status != PJ_EPENDING)
+ goto on_error;
+
+
+ /* Looks like everything is okay */
+ *p_resolver = resv;
+ return PJ_SUCCESS;
+
+on_error:
+ pj_dns_resolver_destroy(resv, PJ_FALSE);
+ return status;
+}
+
+
+/*
+ * Destroy DNS resolver instance.
+ */
+PJ_DEF(pj_status_t) pj_dns_resolver_destroy( pj_dns_resolver *resolver,
+ pj_bool_t notify)
+{
+ PJ_ASSERT_RETURN(resolver, PJ_EINVAL);
+
+ if (notify) {
+ /*
+ * Notify pending queries if requested.
+ */
+ pj_hash_iterator_t it_buf, *it;
+
+ it = pj_hash_first(resolver->hquerybyid, &it_buf);
+ while (it) {
+ pj_dns_async_query *q = pj_hash_this(resolver->hquerybyid, it);
+ pj_dns_async_query *cq;
+ if (q->cb)
+ (*q->cb)(q->user_data, PJ_ECANCELLED, NULL);
+
+ cq = q->child_head.next;
+ while (cq != (pj_dns_async_query*)&q->child_head) {
+ if (cq->cb)
+ (*cq->cb)(cq->user_data, PJ_ECANCELLED, NULL);
+ cq = cq->next;
+ }
+ it = pj_hash_next(resolver->hquerybyid, it);
+ }
+ }
+
+ if (resolver->own_timer && resolver->timer) {
+ pj_timer_heap_destroy(resolver->timer);
+ resolver->timer = NULL;
+ }
+
+ if (resolver->own_ioqueue && resolver->ioqueue) {
+ pj_ioqueue_destroy(resolver->ioqueue);
+ resolver->ioqueue = NULL;
+ }
+
+ if (resolver->udp_key != NULL) {
+ pj_ioqueue_unregister(resolver->udp_key);
+ resolver->udp_key = NULL;
+ resolver->udp_sock = PJ_INVALID_SOCKET;
+ } else if (resolver->udp_sock != PJ_INVALID_SOCKET) {
+ pj_sock_close(resolver->udp_sock);
+ resolver->udp_sock = PJ_INVALID_SOCKET;
+ }
+
+ if (resolver->mutex) {
+ pj_mutex_destroy(resolver->mutex);
+ resolver->mutex = NULL;
+ }
+
+ if (resolver->pool) {
+ pj_pool_t *pool = resolver->pool;
+ resolver->pool = NULL;
+ pj_pool_release(pool);
+ }
+ return PJ_SUCCESS;
+}
+
+
+
+/*
+ * Configure name servers for the DNS resolver.
+ */
+PJ_DEF(pj_status_t) pj_dns_resolver_set_ns( pj_dns_resolver *resolver,
+ unsigned count,
+ const pj_str_t servers[],
+ const pj_uint16_t ports[])
+{
+ unsigned i;
+ pj_time_val now;
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(resolver && count && servers, PJ_EINVAL);
+
+ pj_mutex_lock(resolver->mutex);
+
+ if (count > PJ_DNS_RESOLVER_MAX_NS)
+ count = PJ_DNS_RESOLVER_MAX_NS;
+
+ resolver->ns_count = 0;
+ pj_bzero(resolver->ns, sizeof(resolver->ns));
+
+ pj_gettimeofday(&now);
+
+ for (i=0; i<count; ++i) {
+ struct nameserver *ns = &resolver->ns[i];
+
+ status = pj_sockaddr_in_init(&ns->addr, &servers[i],
+ (pj_uint16_t)(ports ? ports[i] : PORT));
+ if (status != PJ_SUCCESS) {
+ pj_mutex_unlock(resolver->mutex);
+ return PJLIB_UTIL_EDNSINNSADDR;
+ }
+
+ ns->state = STATE_ACTIVE;
+ ns->state_expiry = now;
+ ns->rt_delay.sec = 10;
+ }
+
+ resolver->ns_count = count;
+
+ pj_mutex_unlock(resolver->mutex);
+ return PJ_SUCCESS;
+}
+
+
+
+/*
+ * Modify the resolver settings.
+ */
+PJ_DEF(pj_status_t) pj_dns_resolver_set_settings(pj_dns_resolver *resolver,
+ const pj_dns_settings *st)
+{
+ PJ_ASSERT_RETURN(resolver && st, PJ_EINVAL);
+
+ pj_mutex_lock(resolver->mutex);
+ pj_memcpy(&resolver->settings, st, sizeof(*st));
+ pj_mutex_unlock(resolver->mutex);
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Get the resolver current settings.
+ */
+PJ_DEF(pj_status_t) pj_dns_resolver_get_settings( pj_dns_resolver *resolver,
+ pj_dns_settings *st)
+{
+ PJ_ASSERT_RETURN(resolver && st, PJ_EINVAL);
+
+ pj_mutex_lock(resolver->mutex);
+ pj_memcpy(st, &resolver->settings, sizeof(*st));
+ pj_mutex_unlock(resolver->mutex);
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Poll for events from the resolver.
+ */
+PJ_DEF(void) pj_dns_resolver_handle_events(pj_dns_resolver *resolver,
+ const pj_time_val *timeout)
+{
+ PJ_ASSERT_ON_FAIL(resolver, return);
+
+ pj_mutex_lock(resolver->mutex);
+ pj_timer_heap_poll(resolver->timer, NULL);
+ pj_mutex_unlock(resolver->mutex);
+
+ pj_ioqueue_poll(resolver->ioqueue, timeout);
+}
+
+
+/* Get one query node from the free node, if any, or allocate
+ * a new one.
+ */
+static pj_dns_async_query *alloc_qnode(pj_dns_resolver *resolver,
+ unsigned options,
+ void *user_data,
+ pj_dns_callback *cb)
+{
+ pj_dns_async_query *q;
+
+ /* Merge query options with resolver options */
+ options |= resolver->settings.options;
+
+ if (!pj_list_empty(&resolver->query_free_nodes)) {
+ q = resolver->query_free_nodes.next;
+ pj_list_erase(q);
+ pj_bzero(q, sizeof(*q));
+ } else {
+ q = pj_pool_zalloc(resolver->pool, sizeof(*q));
+ }
+
+ /* Init query */
+ q->resolver = resolver;
+ q->options = options;
+ q->user_data = user_data;
+ q->cb = cb;
+ pj_list_init(&q->child_head);
+
+ return q;
+}
+
+
+/*
+ * Transmit query.
+ */
+static pj_status_t transmit_query(pj_dns_resolver *resolver,
+ pj_dns_async_query *q)
+{
+ unsigned pkt_size;
+ unsigned i, server_cnt;
+ unsigned servers[PJ_DNS_RESOLVER_MAX_NS];
+ pj_time_val now;
+ pj_str_t name;
+ pj_time_val delay;
+ pj_status_t status;
+
+ /* Create DNS query packet */
+ pkt_size = sizeof(resolver->udp_tx_pkt);
+ name = pj_str(q->key.name);
+ status = pj_dns_make_query(resolver->udp_tx_pkt, &pkt_size,
+ q->id, q->key.qtype, &name);
+ if (status != PJ_SUCCESS) {
+ return status;
+ }
+
+ /* Select which nameserver(s) to send requests to. */
+ server_cnt = PJ_ARRAY_SIZE(servers);
+ status = select_nameservers(resolver, &server_cnt, servers);
+ if (status != PJ_SUCCESS) {
+ return status;
+ }
+
+ if (server_cnt == 0) {
+ return PJLIB_UTIL_EDNSNOWORKINGNS;
+ }
+
+ /* Start retransmit/timeout timer for the query */
+ pj_assert(q->timer_entry.id == 0);
+ q->timer_entry.id = 1;
+ q->timer_entry.user_data = q;
+ q->timer_entry.cb = &on_timeout;
+
+ delay.sec = 0;
+ delay.msec = resolver->settings.qretr_delay;
+ pj_time_val_normalize(&delay);
+ status = pj_timer_heap_schedule(resolver->timer, &q->timer_entry, &delay);
+ if (status != PJ_SUCCESS) {
+ return status;
+ }
+
+ /* Get current time. */
+ pj_gettimeofday(&now);
+
+ /* Send the packet to name servers */
+ for (i=0; i<server_cnt; ++i) {
+ pj_ssize_t sent = (pj_ssize_t) pkt_size;
+ struct nameserver *ns = &resolver->ns[servers[i]];
+
+ pj_sock_sendto(resolver->udp_sock, resolver->udp_tx_pkt, &sent, 0,
+ &resolver->ns[servers[i]].addr, sizeof(pj_sockaddr_in));
+
+ PJ_LOG(4,(resolver->name.ptr,
+ "%s %d bytes to NS %d (%s:%d): DNS %s query for %s",
+ (q->transmit_cnt==0? "Transmitting":"Re-transmitting"),
+ (int)sent, servers[i],
+ pj_inet_ntoa(ns->addr.sin_addr),
+ (int)pj_ntohs(ns->addr.sin_port),
+ pj_dns_get_type_name(q->key.qtype),
+ q->key.name));
+
+ if (ns->q_id == 0) {
+ ns->q_id = q->id;
+ ns->sent_time = now;
+ }
+ }
+
+ ++q->transmit_cnt;
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Initialize resource key for hash table lookup.
+ */
+static void init_res_key(struct res_key *key, int type, const pj_str_t *name)
+{
+ unsigned i, len;
+ char *dst = key->name;
+ const char *src = name->ptr;
+
+ pj_bzero(key, sizeof(struct res_key));
+ key->qtype = (pj_uint16_t)type;
+
+ len = name->slen;
+ if (len > PJ_MAX_HOSTNAME) len = PJ_MAX_HOSTNAME;
+
+ /* Copy key, in lowercase */
+ for (i=0; i<len; ++i) {
+ *dst++ = (char)pj_tolower(*src++);
+ }
+}
+
+
+/*
+ * Create and start asynchronous DNS query for a single resource.
+ */
+PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver,
+ const pj_str_t *name,
+ int type,
+ unsigned options,
+ pj_dns_callback *cb,
+ void *user_data,
+ pj_dns_async_query **p_query)
+{
+ pj_time_val now;
+ struct res_key key;
+ struct cached_res *cache;
+ pj_dns_async_query *q;
+ pj_uint32_t hval;
+ pj_status_t status = PJ_SUCCESS;
+
+ /* Validate arguments */
+ PJ_ASSERT_RETURN(resolver && name && type, PJ_EINVAL);
+
+ /* Check name is not too long. */
+ PJ_ASSERT_RETURN(name->slen>0 && name->slen < PJ_MAX_HOSTNAME,
+ PJ_ENAMETOOLONG);
+
+ /* Check type */
+ PJ_ASSERT_RETURN(type > 0 && type < 0xFFFF, PJ_EINVAL);
+
+ if (p_query)
+ *p_query = NULL;
+
+ /* Build resource key for looking up hash tables */
+ init_res_key(&key, type, name);
+
+ /* Start working with the resolver */
+ pj_mutex_lock(resolver->mutex);
+
+ /* Get current time. */
+ pj_gettimeofday(&now);
+
+ /* First, check if we have cached response for the specified name/type,
+ * and the cached entry has not expired.
+ */
+ hval = 0;
+ cache = pj_hash_get(resolver->hrescache, &key, sizeof(key), &hval);
+ if (cache) {
+ /* We've found a cached entry. */
+
+ /* Check for expiration */
+ if (PJ_TIME_VAL_GT(cache->expiry_time, now)) {
+
+ /* Log */
+ PJ_LOG(5,(resolver->name.ptr,
+ "Picked up DNS %s record for %.*s in cache",
+ pj_dns_get_type_name(type),
+ (int)name->slen, name->ptr));
+
+ /* Map DNS Rcode in the response into PJLIB status name space */
+ status = PJ_DNS_GET_RCODE(cache->pkt->hdr.flags);
+ status = PJ_STATUS_FROM_DNS_RCODE(status);
+
+ /* This cached response is still valid. Just return this
+ * response to caller.
+ */
+ if (cb) {
+ (*cb)(user_data, status, cache->pkt);
+ }
+
+ /* Done. No host resolution is necessary */
+
+ /* Must return PJ_SUCCESS */
+ status = PJ_SUCCESS;
+
+ goto on_return;
+ }
+
+ /* At this point, we have a cached entry, but this entry has expired.
+ * Remove this entry from the cached list.
+ */
+ pj_hash_set(NULL, resolver->hrescache, &key, sizeof(key), 0, NULL);
+
+ /* Store the entry into free nodes */
+ pj_list_push_back(&resolver->res_free_nodes, cache);
+
+ /* Must continue with creating a query now */
+ }
+
+ /* Next, check if we have pending query on the same resource */
+ q = pj_hash_get(resolver->hquerybyres, &key, sizeof(key), NULL);
+ if (q) {
+ /* Yes, there's another pending query to the same key.
+ * Just create a new child query and add this query to
+ * pending query's child queries.
+ */
+ pj_dns_async_query *nq;
+
+ nq = alloc_qnode(resolver, options, user_data, cb);
+ pj_list_push_back(&q->child_head, nq);
+
+ /* Done. This child query will be notified once the "parent"
+ * query completes.
+ */
+ status = PJ_SUCCESS;
+ goto on_return;
+ }
+
+ /* There's no pending query to the same key, initiate a new one. */
+ q = alloc_qnode(resolver, options, user_data, cb);
+
+ /* Save the ID and key */
+ q->id = resolver->last_id++;
+ if (resolver->last_id == 0)
+ resolver->last_id = 1;
+ pj_memcpy(&q->key, &key, sizeof(struct res_key));
+
+ /* Send the query */
+ status = transmit_query(resolver, q);
+ if (status != PJ_SUCCESS) {
+ pj_list_push_back(&resolver->query_free_nodes, q);
+ goto on_return;
+ }
+
+ /* Add query entry to the hash tables */
+ pj_hash_set_np(resolver->hquerybyid, &q->id, sizeof(q->id),
+ 0, q->hbufid, q);
+ pj_hash_set_np(resolver->hquerybyres, &q->key, sizeof(q->key),
+ 0, q->hbufkey, q);
+
+ if (p_query)
+ *p_query = q;
+
+on_return:
+ pj_mutex_unlock(resolver->mutex);
+ return status;
+}
+
+
+/*
+ * Cancel a pending query.
+ */
+PJ_DEF(pj_status_t) pj_dns_resolver_cancel_query(pj_dns_async_query *query,
+ pj_bool_t notify)
+{
+ pj_dns_callback *cb;
+
+ PJ_ASSERT_RETURN(query, PJ_EINVAL);
+
+ pj_mutex_lock(query->resolver->mutex);
+
+ cb = query->cb;
+ query->cb = NULL;
+
+ if (notify)
+ (*cb)(query->user_data, PJ_ECANCELLED, NULL);
+
+ pj_mutex_unlock(query->resolver->mutex);
+ return PJ_SUCCESS;
+}
+
+
+
+/* Set nameserver state */
+static void set_nameserver_state(pj_dns_resolver *resolver,
+ unsigned index,
+ enum ns_state state,
+ const pj_time_val *now)
+{
+ struct nameserver *ns = &resolver->ns[index];
+
+ ns->state = state;
+ ns->state_expiry = *now;
+
+ if (state == STATE_PROBING)
+ ns->state_expiry.sec += ((PJ_DNS_RESOLVER_QUERY_RETRANSMIT_COUNT + 2) *
+ PJ_DNS_RESOLVER_QUERY_RETRANSMIT_DELAY) / 1000;
+ else if (state == STATE_ACTIVE)
+ ns->state_expiry.sec += PJ_DNS_RESOLVER_GOOD_NS_TTL;
+ else
+ ns->state_expiry.sec += PJ_DNS_RESOLVER_BAD_NS_TTL;
+
+}
+
+
+/* Select which nameserver(s) to use. Note this may return multiple
+ * name servers. The algorithm to select which nameservers to be
+ * sent the request to is as follows:
+ * - select the first nameserver that is known to be good for the
+ * last PJ_DNS_RESOLVER_GOOD_NS_TTL interval.
+ * - for all NSes, if last_known_good >= PJ_DNS_RESOLVER_GOOD_NS_TTL,
+ * include the NS to re-check again that the server is still good,
+ * unless the NS is known to be bad in the last PJ_DNS_RESOLVER_BAD_NS_TTL
+ * interval.
+ * - for all NSes, if last_known_bad >= PJ_DNS_RESOLVER_BAD_NS_TTL,
+ * also include the NS to re-check again that the server is still bad.
+ */
+static pj_status_t select_nameservers(pj_dns_resolver *resolver,
+ unsigned *count,
+ unsigned servers[])
+{
+ unsigned i, max_count=*count;
+ int min;
+ pj_time_val now;
+
+ pj_assert(max_count > 0);
+
+ *count = 0;
+ servers[0] = 0xFFFF;
+
+ /* Check that nameservers are configured. */
+ if (resolver->ns_count == 0)
+ return PJLIB_UTIL_EDNSNONS;
+
+ pj_gettimeofday(&now);
+
+ /* Select one Active nameserver with best response time. */
+ for (min=-1, i=0; i<resolver->ns_count; ++i) {
+ struct nameserver *ns = &resolver->ns[i];
+
+ if (ns->state != STATE_ACTIVE)
+ continue;
+
+ if (min == -1)
+ min = i;
+ else if (PJ_TIME_VAL_LT(ns->rt_delay, resolver->ns[min].rt_delay))
+ min = i;
+ }
+ if (min != -1) {
+ servers[0] = min;
+ ++(*count);
+ }
+
+ /* Scan nameservers. */
+ for (i=0; i<resolver->ns_count && *count < max_count; ++i) {
+ struct nameserver *ns = &resolver->ns[i];
+
+ if (PJ_TIME_VAL_LTE(ns->state_expiry, now)) {
+ if (ns->state == STATE_PROBING) {
+ set_nameserver_state(resolver, i, STATE_BAD, &now);
+ } else {
+ set_nameserver_state(resolver, i, STATE_PROBING, &now);
+ if ((int)i != min) {
+ servers[*count] = i;
+ ++(*count);
+ }
+ }
+ } else if (ns->state == STATE_PROBING && (int)i != min) {
+ servers[*count] = i;
+ ++(*count);
+ }
+ }
+
+ return PJ_SUCCESS;
+}
+
+
+/* Update name server status */
+static void report_nameserver_status(pj_dns_resolver *resolver,
+ const pj_sockaddr_in *ns_addr,
+ const pj_dns_parsed_packet *pkt)
+{
+ unsigned i;
+ int rcode;
+ pj_uint32_t q_id;
+ pj_time_val now;
+ pj_bool_t is_good;
+
+ /* Only mark nameserver as "bad" if it returned non-parseable response or
+ * it returned the following status codes
+ */
+ if (pkt) {
+ rcode = PJ_DNS_GET_RCODE(pkt->hdr.flags);
+ q_id = pkt->hdr.id;
+ } else {
+ rcode = 0;
+ q_id = (pj_uint32_t)-1;
+ }
+
+ if (!pkt || rcode == PJ_DNS_RCODE_SERVFAIL ||
+ rcode == PJ_DNS_RCODE_REFUSED ||
+ rcode == PJ_DNS_RCODE_NOTAUTH)
+ {
+ is_good = PJ_FALSE;
+ } else {
+ is_good = PJ_TRUE;
+ }
+
+
+ /* Mark time */
+ pj_gettimeofday(&now);
+
+ /* Recheck all nameservers. */
+ for (i=0; i<resolver->ns_count; ++i) {
+ struct nameserver *ns = &resolver->ns[i];
+
+ if (ns->addr.sin_addr.s_addr == ns_addr->sin_addr.s_addr &&
+ ns->addr.sin_port == ns_addr->sin_port &&
+ ns->addr.sin_family == ns_addr->sin_family)
+ {
+ if (q_id == ns->q_id) {
+ /* Calculate response time */
+ pj_time_val rt = now;
+ PJ_TIME_VAL_SUB(rt, ns->sent_time);
+ ns->rt_delay = rt;
+ ns->q_id = 0;
+ }
+ set_nameserver_state(resolver, i,
+ (is_good ? STATE_ACTIVE : STATE_BAD), &now);
+ break;
+ }
+ }
+}
+
+
+/* Update response cache */
+static void update_res_cache(pj_dns_resolver *resolver,
+ const struct res_key *key,
+ pj_status_t status,
+ pj_bool_t set_expiry,
+ const pj_dns_parsed_packet *pkt)
+{
+ struct cached_res *cache;
+ pj_pool_t *res_pool;
+ pj_uint32_t hval=0, ttl;
+ PJ_USE_EXCEPTION;
+
+ /* If status is unsuccessful, clear the same entry from the cache */
+ if (status != PJ_SUCCESS) {
+ cache = pj_hash_get(resolver->hrescache, key, sizeof(*key), &hval);
+ if (cache)
+ pj_list_push_back(&resolver->res_free_nodes, cache);
+ pj_hash_set(NULL, resolver->hrescache, key, sizeof(*key), hval, NULL);
+ }
+
+
+ /* Calculate expiration time. */
+ if (set_expiry) {
+ if (pkt->hdr.anscount == 0) {
+ /* If we don't have answers for the name, then give a different
+ * ttl value (note: PJ_DNS_RESOLVER_INVALID_TTL may be zero,
+ * which means that invalid names won't be kept in the cache)
+ */
+ ttl = PJ_DNS_RESOLVER_INVALID_TTL;
+
+ } else {
+ /* Otherwise get the minimum TTL from the answers */
+ unsigned i;
+ ttl = 0xFFFFFFFF;
+ for (i=0; i<pkt->hdr.anscount; ++i) {
+ if (pkt->ans[i].ttl < ttl)
+ ttl = pkt->ans[i].ttl;
+ }
+ }
+ } else {
+ ttl = 0xFFFFFFFF;
+ }
+
+ /* Apply maximum TTL */
+ if (ttl > resolver->settings.cache_max_ttl)
+ ttl = resolver->settings.cache_max_ttl;
+
+ /* If TTL is zero, clear the same entry in the hash table */
+ if (ttl == 0) {
+ cache = pj_hash_get(resolver->hrescache, key, sizeof(*key), &hval);
+ if (cache)
+ pj_list_push_back(&resolver->res_free_nodes, cache);
+ pj_hash_set(NULL, resolver->hrescache, key, sizeof(*key), hval, NULL);
+ return;
+ }
+
+ /* Get a cache response entry */
+ cache = pj_hash_get(resolver->hrescache, key, sizeof(*key), &hval);
+ if (cache == NULL) {
+ if (!pj_list_empty(&resolver->res_free_nodes)) {
+ cache = resolver->res_free_nodes.next;
+ pj_list_erase(cache);
+ } else {
+ cache = pj_pool_zalloc(resolver->pool, sizeof(*cache));
+ }
+ }
+
+ /* Duplicate the packet */
+ res_pool = pj_pool_create_on_buf("respool", cache->buf, sizeof(cache->buf));
+ PJ_TRY {
+ cache->pkt = NULL;
+ pj_dns_packet_dup(res_pool, pkt, &cache->pkt);
+ }
+ PJ_CATCH_ANY {
+ PJ_LOG(1,(THIS_FILE,
+ "Not enough memory to duplicate DNS response. Response was "
+ "truncated."));
+ }
+ PJ_END;
+
+ /* Calculate expiration time */
+ if (set_expiry) {
+ pj_gettimeofday(&cache->expiry_time);
+ cache->expiry_time.sec += ttl;
+ } else {
+ cache->expiry_time.sec = 0x7FFFFFFFL;
+ cache->expiry_time.msec = 0;
+ }
+
+ /* Copy key to the cached response */
+ pj_memcpy(&cache->key, key, sizeof(*key));
+
+ /* Update the hash table */
+ pj_hash_set_np(resolver->hrescache, &cache->key, sizeof(*key), hval,
+ cache->hbuf, cache);
+}
+
+
+/* Callback to be called when query has timed out */
+static void on_timeout( pj_timer_heap_t *timer_heap,
+ struct pj_timer_entry *entry)
+{
+ pj_dns_resolver *resolver;
+ pj_dns_async_query *q, *cq;
+ pj_status_t status;
+
+ PJ_UNUSED_ARG(timer_heap);
+
+ q = entry->user_data;
+ resolver = q->resolver;
+
+ pj_mutex_lock(resolver->mutex);
+
+ /* Recheck that this query is still pending, since there is a slight
+ * possibility of race condition (timer elapsed while at the same time
+ * response arrives)
+ */
+ if (pj_hash_get(resolver->hquerybyid, &q->id, sizeof(q->id), NULL)==NULL) {
+ /* Yeah, this query is done. */
+ pj_mutex_unlock(resolver->mutex);
+ return;
+ }
+
+ /* Invalidate id. */
+ q->timer_entry.id = 0;
+
+ /* Check to see if we should retransmit instead of time out */
+ if (q->transmit_cnt < PJ_DNS_RESOLVER_QUERY_RETRANSMIT_COUNT) {
+ status = transmit_query(resolver, q);
+ if (status == PJ_SUCCESS) {
+ pj_mutex_unlock(resolver->mutex);
+ return;
+ } else {
+ /* Error occurs */
+ char errmsg[PJ_ERR_MSG_SIZE];
+
+ pj_strerror(status, errmsg, sizeof(errmsg));
+ PJ_LOG(4,(resolver->name.ptr,
+ "Error transmitting request: %s", errmsg));
+
+ /* Let it fallback to timeout section below */
+ }
+ }
+
+ /* Clear hash table entries */
+ pj_hash_set(NULL, resolver->hquerybyid, &q->id, sizeof(q->id), 0, NULL);
+ pj_hash_set(NULL, resolver->hquerybyres, &q->key, sizeof(q->key), 0, NULL);
+
+ /* Call application callback, if any. */
+ if (q->cb)
+ (*q->cb)(q->user_data, PJ_ETIMEDOUT, NULL);
+
+ /* Call application callback for child queries. */
+ cq = q->child_head.next;
+ while (cq != (void*)&q->child_head) {
+ if (cq->cb)
+ (*cq->cb)(cq->user_data, PJ_ETIMEDOUT, NULL);
+ cq = cq->next;
+ }
+
+ /* Clear data */
+ q->timer_entry.id = 0;
+ q->user_data = NULL;
+
+ /* Put child entries into recycle list */
+ cq = q->child_head.next;
+ while (cq != (void*)&q->child_head) {
+ pj_dns_async_query *next = cq->next;
+ pj_list_push_back(&resolver->query_free_nodes, cq);
+ cq = next;
+ }
+
+ /* Put query entry into recycle list */
+ pj_list_push_back(&resolver->query_free_nodes, q);
+
+ pj_mutex_unlock(resolver->mutex);
+}
+
+
+/* Callback from ioqueue when packet is received */
+static void on_read_complete(pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_ssize_t bytes_read)
+{
+ pj_dns_resolver *resolver;
+ pj_pool_t *pool;
+ pj_dns_parsed_packet *dns_pkt;
+ pj_dns_async_query *q;
+ pj_status_t status;
+ PJ_USE_EXCEPTION;
+
+
+ resolver = pj_ioqueue_get_user_data(key);
+ pj_mutex_lock(resolver->mutex);
+
+
+ /* Check for errors */
+ if (bytes_read < 0) {
+ char errmsg[PJ_ERR_MSG_SIZE];
+
+ status = -bytes_read;
+ pj_strerror(status, errmsg, sizeof(errmsg));
+ PJ_LOG(4,(resolver->name.ptr,
+ "DNS resolver read error from %s:%d: %s",
+ pj_inet_ntoa(resolver->udp_src_addr.sin_addr),
+ pj_ntohs(resolver->udp_src_addr.sin_port),
+ errmsg));
+
+ goto read_next_packet;
+ }
+
+ PJ_LOG(5,(resolver->name.ptr,
+ "Received %d bytes DNS response from %s:%d",
+ (int)bytes_read,
+ pj_inet_ntoa(resolver->udp_src_addr.sin_addr),
+ pj_ntohs(resolver->udp_src_addr.sin_port)));
+
+
+ /* Check for zero packet */
+ if (bytes_read == 0)
+ goto read_next_packet;
+
+ /* Create temporary pool from a fixed buffer */
+ pool = pj_pool_create_on_buf("restmp", resolver->tmp_pool,
+ sizeof(resolver->tmp_pool));
+
+ /* Parse DNS response */
+ status = -1;
+ dns_pkt = NULL;
+ PJ_TRY {
+ status = pj_dns_parse_packet(pool, resolver->udp_rx_pkt,
+ (unsigned)bytes_read, &dns_pkt);
+ }
+ PJ_CATCH_ANY {
+ status = PJ_ENOMEM;
+ }
+ PJ_END;
+
+ /* Update nameserver status */
+ report_nameserver_status(resolver, &resolver->udp_src_addr, dns_pkt);
+
+ /* Handle parse error */
+ if (status != PJ_SUCCESS) {
+ char errmsg[PJ_ERR_MSG_SIZE];
+
+ pj_strerror(status, errmsg, sizeof(errmsg));
+ PJ_LOG(3,(resolver->name.ptr,
+ "Error parsing DNS response from %s:%d: %s",
+ pj_inet_ntoa(resolver->udp_src_addr.sin_addr),
+ pj_ntohs(resolver->udp_src_addr.sin_port),
+ errmsg));
+ goto read_next_packet;
+ }
+
+ /* Find the query based on the transaction ID */
+ q = pj_hash_get(resolver->hquerybyid, &dns_pkt->hdr.id,
+ sizeof(dns_pkt->hdr.id), NULL);
+ if (!q) {
+ PJ_LOG(5,(resolver->name.ptr,
+ "Unable to find query for DNS response id=%d from %s:%d "
+ "(the query may had been answered by other name servers)",
+ (unsigned)dns_pkt->hdr.id,
+ pj_inet_ntoa(resolver->udp_src_addr.sin_addr),
+ pj_ntohs(resolver->udp_src_addr.sin_port)));
+ goto read_next_packet;
+ }
+
+ /* Map DNS Rcode in the response into PJLIB status name space */
+ status = PJ_STATUS_FROM_DNS_RCODE(PJ_DNS_GET_RCODE(dns_pkt->hdr.flags));
+
+ /* Cancel query timeout timer. */
+ pj_assert(q->timer_entry.id != 0);
+ pj_timer_heap_cancel(resolver->timer, &q->timer_entry);
+ q->timer_entry.id = 0;
+
+ /* Clear hash table entries */
+ pj_hash_set(NULL, resolver->hquerybyid, &q->id, sizeof(q->id), 0, NULL);
+ pj_hash_set(NULL, resolver->hquerybyres, &q->key, sizeof(q->key), 0, NULL);
+
+ /* Notify applications first, to allow application to modify the
+ * record before it is saved to the hash table.
+ */
+ if (q->cb)
+ (*q->cb)(q->user_data, status, dns_pkt);
+
+ /* If query has subqueries, notify subqueries's application callback */
+ if (!pj_list_empty(&q->child_head)) {
+ pj_dns_async_query *child_q;
+
+ child_q = q->child_head.next;
+ while (child_q != (pj_dns_async_query*)&q->child_head) {
+ if (child_q->cb)
+ (*child_q->cb)(child_q->user_data, status, dns_pkt);
+ child_q = child_q->next;
+ }
+ }
+
+ /* We don't need NS and query section in the packet, so trim them. */
+ dns_pkt->hdr.qdcount = 0;
+ dns_pkt->hdr.nscount = 0;
+
+ /* Save/update response cache. */
+ update_res_cache(resolver, &q->key, status, PJ_TRUE, dns_pkt);
+
+ /* Recycle query objects, starting with the child queries */
+ if (!pj_list_empty(&q->child_head)) {
+ pj_dns_async_query *child_q;
+
+ child_q = q->child_head.next;
+ while (child_q != (pj_dns_async_query*)&q->child_head) {
+ pj_dns_async_query *next = child_q->next;
+ pj_list_erase(child_q);
+ pj_list_push_back(&resolver->query_free_nodes, child_q);
+ child_q = next;
+ }
+ }
+ pj_list_push_back(&resolver->query_free_nodes, q);
+
+read_next_packet:
+ bytes_read = sizeof(resolver->udp_rx_pkt);
+ resolver->udp_addr_len = sizeof(resolver->udp_src_addr);
+ status = pj_ioqueue_recvfrom(resolver->udp_key, op_key,
+ resolver->udp_rx_pkt,
+ &bytes_read, PJ_IOQUEUE_ALWAYS_ASYNC,
+ &resolver->udp_src_addr,
+ &resolver->udp_addr_len);
+ if (status != PJ_EPENDING) {
+ char errmsg[PJ_ERR_MSG_SIZE];
+
+ pj_strerror(status, errmsg, sizeof(errmsg));
+ PJ_LOG(4,(resolver->name.ptr, "DNS resolver ioqueue read error: %s",
+ errmsg));
+
+ pj_assert(!"Unhandled error");
+ }
+
+ pj_mutex_unlock(resolver->mutex);
+}
+
+
+/*
+ * Put the specified DNS packet into DNS cache. This function is mainly used
+ * for testing the resolver, however it can also be used to inject entries
+ * into the resolver.
+ */
+PJ_DEF(pj_status_t) pj_dns_resolver_add_entry( pj_dns_resolver *resolver,
+ const pj_dns_parsed_packet *pkt,
+ pj_bool_t set_ttl)
+{
+ struct res_key key;
+
+ /* Sanity check */
+ PJ_ASSERT_RETURN(resolver && pkt, PJ_EINVAL);
+
+ /* Packet must be a DNS response */
+ PJ_ASSERT_RETURN(PJ_DNS_GET_QR(pkt->hdr.flags) & 1, PJ_EINVAL);
+
+ /* Make sure there are answers in the packet */
+ PJ_ASSERT_RETURN(pkt->hdr.anscount && pkt->ans ||
+ pkt->hdr.qdcount && pkt->q,
+ PJLIB_UTIL_EDNSNOANSWERREC);
+
+ pj_mutex_lock(resolver->mutex);
+
+ /* Build resource key for looking up hash tables */
+ pj_bzero(&key, sizeof(struct res_key));
+ if (pkt->hdr.anscount) {
+ /* Make sure name is not too long. */
+ PJ_ASSERT_RETURN(pkt->ans[0].name.slen < PJ_MAX_HOSTNAME,
+ PJ_ENAMETOOLONG);
+
+ init_res_key(&key, pkt->ans[0].type, &pkt->ans[0].name);
+
+ } else {
+ /* Make sure name is not too long. */
+ PJ_ASSERT_RETURN(pkt->q[0].name.slen < PJ_MAX_HOSTNAME,
+ PJ_ENAMETOOLONG);
+
+ init_res_key(&key, pkt->q[0].type, &pkt->q[0].name);
+ }
+
+ /* Insert entry. */
+ update_res_cache(resolver, &key, PJ_SUCCESS, set_ttl, pkt);
+
+ pj_mutex_unlock(resolver->mutex);
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Get the total number of response in the response cache.
+ */
+PJ_DEF(unsigned) pj_dns_resolver_get_cached_count(pj_dns_resolver *resolver)
+{
+ unsigned count;
+
+ PJ_ASSERT_RETURN(resolver, 0);
+
+ pj_mutex_lock(resolver->mutex);
+ count = pj_hash_count(resolver->hrescache);
+ pj_mutex_unlock(resolver->mutex);
+
+ return count;
+}
+
+
+/*
+ * Dump resolver state to the log.
+ */
+PJ_DEF(void) pj_dns_resolver_dump(pj_dns_resolver *resolver,
+ pj_bool_t detail)
+{
+#if PJ_LOG_MAX_LEVEL >= 3
+ unsigned i;
+ pj_time_val now;
+
+ pj_mutex_lock(resolver->mutex);
+
+ pj_gettimeofday(&now);
+
+ PJ_LOG(3,(resolver->name.ptr, " Dumping resolver state:"));
+
+ PJ_LOG(3,(resolver->name.ptr, " Name servers:"));
+ for (i=0; i<resolver->ns_count; ++i) {
+ const char *state_names[] = { "probing", "active", "bad"};
+ struct nameserver *ns = &resolver->ns[i];
+
+ PJ_LOG(3,(resolver->name.ptr,
+ " NS %d: %s:%d (state=%s until %ds, rtt=%d ms)",
+ i, pj_inet_ntoa(ns->addr.sin_addr),
+ pj_ntohs(ns->addr.sin_port),
+ state_names[ns->state],
+ ns->state_expiry.sec - now.sec,
+ PJ_TIME_VAL_MSEC(ns->rt_delay)));
+ }
+
+ PJ_LOG(3,(resolver->name.ptr, " Nb. of cached responses: %u",
+ pj_hash_count(resolver->hrescache)));
+ if (detail) {
+ pj_hash_iterator_t itbuf, *it;
+ it = pj_hash_first(resolver->hrescache, &itbuf);
+ while (it) {
+ struct cached_res *cache = pj_hash_this(resolver->hrescache, it);
+ PJ_LOG(3,(resolver->name.ptr,
+ " Type %s: %s",
+ pj_dns_get_type_name(cache->key.qtype),
+ cache->key.name));
+ it = pj_hash_next(resolver->hrescache, it);
+ }
+ }
+ PJ_LOG(3,(resolver->name.ptr, " Nb. of cached response free nodes: %u",
+ pj_list_size(&resolver->res_free_nodes)));
+ PJ_LOG(3,(resolver->name.ptr, " Nb. of pending queries: %u (%u)",
+ pj_hash_count(resolver->hquerybyid),
+ pj_hash_count(resolver->hquerybyres)));
+ if (detail) {
+ pj_hash_iterator_t itbuf, *it;
+ it = pj_hash_first(resolver->hquerybyid, &itbuf);
+ while (it) {
+ struct pj_dns_async_query *q;
+ q = pj_hash_this(resolver->hquerybyid, it);
+ PJ_LOG(3,(resolver->name.ptr,
+ " Type %s: %s",
+ pj_dns_get_type_name(q->key.qtype),
+ q->key.name));
+ it = pj_hash_next(resolver->hquerybyid, it);
+ }
+ }
+ PJ_LOG(3,(resolver->name.ptr, " Nb. of pending query free nodes: %u",
+ pj_list_size(&resolver->query_free_nodes)));
+ PJ_LOG(3,(resolver->name.ptr, " Nb. of timer entries: %u",
+ pj_timer_heap_count(resolver->timer)));
+ PJ_LOG(3,(resolver->name.ptr, " Pool capacity: %d, used size: %d",
+ pj_pool_get_capacity(resolver->pool),
+ pj_pool_get_used_size(resolver->pool)));
+
+ pj_mutex_unlock(resolver->mutex);
+#endif
+}
+
diff --git a/pjlib/src/pj/pool_buf.c b/pjlib/src/pj/pool_buf.c
index 13c9821a..6439926e 100644
--- a/pjlib/src/pj/pool_buf.c
+++ b/pjlib/src/pj/pool_buf.c
@@ -72,6 +72,7 @@ PJ_DEF(pj_pool_t*) pj_pool_create_on_buf(const char *name,
param.size = size;
pj_thread_local_set(tls, &param);
- return pj_pool_create_int(&stack_based_factory, name, size, 0, NULL);
+ return pj_pool_create_int(&stack_based_factory, name, size, 0,
+ pj_pool_factory_default_policy.callback);
}
diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c
index e3d9a33c..268eb502 100644
--- a/pjsip-apps/src/pjsua/pjsua_app.c
+++ b/pjsip-apps/src/pjsua/pjsua_app.c
@@ -126,6 +126,8 @@ static void usage(void)
puts (" (Hint: the IP may be the public IP of the NAT/router)");
puts (" --no-tcp Disable TCP transport.");
puts (" --no-udp Disable UDP transport.");
+ puts (" --nameserver=NS Add the specified nameserver to enable SRV resolution");
+ puts (" This option can be specified multiple times.");
puts (" --outbound=url Set the URL of global outbound proxy server");
puts (" May be specified multiple times");
puts (" --use-stun1=host[:port]");
@@ -276,7 +278,7 @@ static pj_status_t parse_args(int argc, char *argv[],
OPT_LOCAL_PORT, OPT_IP_ADDR, OPT_PROXY, OPT_OUTBOUND_PROXY,
OPT_REGISTRAR, OPT_REG_TIMEOUT, OPT_PUBLISH, OPT_ID, OPT_CONTACT,
OPT_REALM, OPT_USERNAME, OPT_PASSWORD,
- OPT_USE_STUN1, OPT_USE_STUN2,
+ OPT_NAMESERVER, OPT_USE_STUN1, OPT_USE_STUN2,
OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE,
OPT_AUTO_ANSWER, OPT_AUTO_HANGUP, OPT_AUTO_PLAY, OPT_AUTO_LOOP,
OPT_AUTO_CONF, OPT_CLOCK_RATE,
@@ -309,6 +311,7 @@ static pj_status_t parse_args(int argc, char *argv[],
{ "realm", 1, 0, OPT_REALM},
{ "username", 1, 0, OPT_USERNAME},
{ "password", 1, 0, OPT_PASSWORD},
+ { "nameserver", 1, 0, OPT_NAMESERVER},
{ "use-stun1", 1, 0, OPT_USE_STUN1},
{ "use-stun2", 1, 0, OPT_USE_STUN2},
{ "add-buddy", 1, 0, OPT_ADD_BUDDY},
@@ -549,6 +552,14 @@ static pj_status_t parse_args(int argc, char *argv[],
cur_acc->cred_count++;
break;
+ case OPT_NAMESERVER: /* nameserver */
+ cfg->cfg.nameserver[cfg->cfg.nameserver_count++] = pj_str(pj_optarg);
+ if (cfg->cfg.nameserver_count > PJ_ARRAY_SIZE(cfg->cfg.nameserver)) {
+ PJ_LOG(1,(THIS_FILE, "Error: too many nameservers"));
+ return PJ_ETOOMANY;
+ }
+ break;
+
case OPT_USE_STUN1: /* STUN server 1 */
p = pj_ansi_strchr(pj_optarg, ':');
if (p) {
diff --git a/pjsip/build/Makefile b/pjsip/build/Makefile
index 81c2cb2e..dad39451 100644
--- a/pjsip/build/Makefile
+++ b/pjsip/build/Makefile
@@ -88,7 +88,8 @@ export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT
# Defines for building test application
#
export TEST_SRCDIR = ../src/test-pjsip
-export TEST_OBJS += dlg_core_test.o msg_err_test.o msg_logger.o msg_test.o \
+export TEST_OBJS += dlg_core_test.o dns_test.o msg_err_test.o \
+ msg_logger.o msg_test.o \
test.o transport_loop_test.o transport_tcp_test.o \
transport_test.o transport_udp_test.o \
tsx_basic_test.o tsx_bench.o tsx_uac_test.o \
diff --git a/pjsip/build/test_pjsip.dsp b/pjsip/build/test_pjsip.dsp
index 82f10ac3..27814458 100644
--- a/pjsip/build/test_pjsip.dsp
+++ b/pjsip/build/test_pjsip.dsp
@@ -93,6 +93,10 @@ SOURCE="..\src\test-pjsip\dlg_core_test.c"
# End Source File
# Begin Source File
+SOURCE="..\src\test-pjsip\dns_test.c"
+# End Source File
+# Begin Source File
+
SOURCE="..\src\test-pjsip\main.c"
# End Source File
# Begin Source File
diff --git a/pjsip/include/pjsip/sip_config.h b/pjsip/include/pjsip/sip_config.h
index e4b402fb..420a2a01 100644
--- a/pjsip/include/pjsip/sip_config.h
+++ b/pjsip/include/pjsip/sip_config.h
@@ -199,6 +199,42 @@
#endif
+/**
+ * This macro specifies whether full DNS resolution should be used.
+ * When enabled, #pjsip_resolve() will perform asynchronous DNS SRV and
+ * A (or AAAA, when IPv6 is supported) resolution to resolve the SIP
+ * domain.
+ *
+ * Note that even when this setting is enabled, asynchronous DNS resolution
+ * will only be done when application calls #pjsip_endpt_create_resolver(),
+ * configure the nameservers with #pj_dns_resolver_set_ns(), and configure
+ * the SIP endpoint's DNS resolver with #pjsip_endpt_set_resolver(). If
+ * these steps are not followed, the domain will be resolved with normal
+ * pj_gethostbyname() function.
+ *
+ * Turning off this setting will save the footprint by about 16KB, since
+ * it should also exclude dns.o and resolve.o from PJLIB-UTIL.
+ *
+ * Default: 1 (enabled)
+ */
+#ifndef PJSIP_HAS_RESOLVER
+# define PJSIP_HAS_RESOLVER 1
+#endif
+
+
+/**
+ * Maximum number of addresses returned by the resolver. The number here
+ * will slightly affect stack usage, since each entry will occupy about
+ * 32 bytes of stack memory.
+ *
+ * Default: 8
+ */
+#ifndef PJSIP_MAX_RESOLVED_ADDRESSES
+# define PJSIP_MAX_RESOLVED_ADDRESSES 8
+#endif
+
+
+
/* Endpoint. */
#define PJSIP_MAX_TIMER_COUNT (2*PJSIP_MAX_TSX_COUNT + 2*PJSIP_MAX_DIALOG_COUNT)
#define PJSIP_POOL_LEN_ENDPT (4000)
diff --git a/pjsip/include/pjsip/sip_endpoint.h b/pjsip/include/pjsip/sip_endpoint.h
index aed4d8a2..6e166090 100644
--- a/pjsip/include/pjsip/sip_endpoint.h
+++ b/pjsip/include/pjsip/sip_endpoint.h
@@ -275,12 +275,51 @@ PJ_DECL(pj_status_t) pjsip_endpt_create_tdata( pjsip_endpoint *endpt,
pjsip_tx_data **p_tdata);
/**
+ * Create the DNS resolver instance. Application creates the DNS
+ * resolver instance, set the nameserver to be used by the DNS
+ * resolver, then set the DNS resolver to be used by the endpoint
+ * by calling #pjsip_endpt_set_resolver().
+ *
+ * @param endpt The SIP endpoint instance.
+ * @param p_resv Pointer to receive the DNS resolver instance.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error
+ * code.
+ */
+PJ_DECL(pj_status_t) pjsip_endpt_create_resolver(pjsip_endpoint *endpt,
+ pj_dns_resolver **p_resv);
+
+/**
+ * Set DNS resolver to be used by the SIP resolver. Application can set
+ * the resolver instance to NULL to disable DNS resolution (perhaps
+ * temporarily). When DNS resolver is disabled, the endpoint will resolve
+ * hostnames with the normal pj_gethostbyname() function.
+ *
+ * @param endpt The SIP endpoint instance.
+ * @param resv The resolver instance to be used by the SIP
+ * endpoint.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error
+ * code.
+ */
+PJ_DECL(pj_status_t) pjsip_endpt_set_resolver(pjsip_endpoint *endpt,
+ pj_dns_resolver *resv);
+
+/**
+ * Get the DNS resolver being used by the SIP resolver.
+ *
+ * @param endpt The SIP endpoint instance.
+ *
+ * @return The DNS resolver instance currently being used
+ * by the SIP endpoint.
+ */
+PJ_DECL(pj_dns_resolver*) pjsip_endpt_get_resolver(pjsip_endpoint *endpt);
+
+/**
* Asynchronously resolve a SIP target host or domain according to rule
* specified in RFC 3263 (Locating SIP Servers). When the resolving operation
* has completed, the callback will be called.
*
- * Note: at the moment we don't have implementation of RFC 3263 yet!
- *
* @param endpt The endpoint instance.
* @param pool The pool to allocate resolver job.
* @param target The target specification to be resolved.
diff --git a/pjsip/include/pjsip/sip_resolve.h b/pjsip/include/pjsip/sip_resolve.h
index 3ebface3..a71dd5b5 100644
--- a/pjsip/include/pjsip/sip_resolve.h
+++ b/pjsip/include/pjsip/sip_resolve.h
@@ -27,26 +27,141 @@
*/
#include <pjsip/sip_types.h>
+#include <pjlib-util/resolver.h>
#include <pj/sock.h>
PJ_BEGIN_DECL
/**
- * @defgroup PJSIP_RESOLVE Server Resolution
+ * @defgroup PJSIP_RESOLVE SIP SRV Server Resolution (RFC 3263 - Locating SIP Servers)
* @ingroup PJSIP_TRANSPORT
* @brief Framework to resolve SIP servers based on RFC 3263.
* @{
- * This is the server resolution framework, which is modelled after
- * RFC 3263 - Locating SIP Servers document. The server resolution
+ * \section PJSIP_RESOLVE_FEATURES Features
+ *
+ * This is the SIP server resolution framework, which is modelled after
+ * RFC 3263 - Locating SIP Servers document. The SIP server resolution
* framework is asynchronous; callback will be called once the server
* address has been resolved (successfully or with errors).
+ *
+ * \subsection PJSIP_RESOLVE_CONFORMANT Conformance to RFC 3263
+ *
+ * The SIP server resolution framework is modelled after RFC 3263 (Locating
+ * SIP Servers) document, and it provides a single function (#pjsip_resolve())
+ * to resolve a domain into actual IP addresses of the servers, by querying
+ * DNS SRV record and DNS A record where necessary.
+ *
+ * The #pjsip_resolve() function performs the server resolution according
+ * to RFC 3263 with some additional fallback mechanisms, as follows:
+ * - if the target name is an IP address, the callback will be called
+ * immediately with the IP address. If port number was specified, this
+ * port number will be used, otherwise the default port number for the
+ * transport will be used (5060 for TCP/UDP, 5061 for TLS) if the transport
+ * is specified. If the transport is not specified, UDP with port number
+ * 5060 will be used.
+ * - if target name is not an IP address but it contains port number,
+ * then the target name is resolved with DNS A (or AAAA, when IPv6 is
+ * supported in the future) query, and the port is taken from the
+ * port number argument. The callback will be called once the DNS A
+ * resolution completes. If the DNS A resolution returns multiple IP
+ * addresses, these IP addresses will be returned to the caller.
+ * - if target name is not an IP address and port number is not specified,
+ * DNS SRV resolution will be performed for the specified name and
+ * transport type (or UDP when transport is not specified),
+ * then followed by DNS A (or AAAA, when IPv6 is supported)
+ * resolution for each target in the SRV record. If DNS SRV
+ * resolution returns error, DNS A (or AAAA) resolution will be
+ * performed for the original target (it is assumed that the target domain
+ * does not support SRV records). Upon successful completion,
+ * application callback will be called with each IP address of the
+ * target selected based on the load-balancing and fail-over criteria
+ * below.
+ *
+ * The above server resolution procedure differs from RFC 3263 in these
+ * regards:
+ * - currently #pjsip_resolve() doesn't support DNS NAPTR record.
+ * - if transport is not specified, it is assumed to be UDP (the proper
+ * behavior is to query the NAPTR record, but we don't support this
+ * yet).
+ *
+ *
+ * \subsection PJSIP_SIP_RESOLVE_FAILOVER_LOADBALANCE Load-Balancing and Fail-Over
+ *
+ * When multiple targets are returned in the DNS SRV response, server entries
+ * are selected based on the following rule (which is described in RFC 2782):
+ * - targets will be sorted based on the priority first.
+ * - for targets with the same priority, #pjsip_resolve() will select
+ * only one target according to its weight. To select this one target,
+ * the function associates running-sum for all targets, and generates
+ * a random number between zero and the total running-sum (inclusive).
+ * The target selected is the first target with running-sum greater than
+ * or equal to this random number.
+ *
+ * The above procedure will select one target for each priority, allowing
+ * application to fail-over to the next target when the previous target fails.
+ * These targets are returned in the #pjsip_server_addresses structure
+ * argument of the callback.
+ *
+ * \subsection PJSIP_SIP_RESOLVE_SIP_FEATURES SIP SRV Resolver Features
+ *
+ * Some features of the SIP resolver:
+ * - DNS SRV entries are returned on sorted order based on priority
+ * to allow failover to the next appropriate server.
+ * - The procedure in RFC 2782 is used to select server with the same
+ * priority to load-balance the servers load.
+ * - A single function (#pjsip_resolve()) performs all server resolution
+ * works, from resolving the SRV records to getting the actual IP addresses
+ * of the servers with DNS A (or AAAA) resolution.
+ * - When multiple DNS SRV records are returned, parallel DNS A (or AAAA)
+ * queries will be issued simultaneously.
+ * - The PJLIB-UTIL DNS resolver provides additional functionality such as
+ * response caching, query aggregation, parallel nameservers, fallback
+ * nameserver, etc., which will be described below.
+ *
+ *
+ * \subsection PJSIP_RESOLVE_DNS_FEATURES DNS Resolver Features
+ *
+ * The PJSIP server resolution framework uses PJLIB-UTIL DNS resolver engine
+ * for performing the asynchronous DNS request. The PJLIB-UTIL DNS resolver
+ * has some useful features, such as:
+ * - queries are asynchronous with configurable timeout,
+ * - query aggregation to combine multiple pending queries to the same
+ * DNS target into a single DNS request (to save message round-trip and
+ * processing),
+ * - response caching with TTL negotiated between the minimum TTL found in
+ * the response and the maximum TTL allowed in the configuration,
+ * - multiple nameservers, with active nameserver is selected from nameserver
+ * which provides the best response time,
+ * - fallback nameserver, with periodic detection of which name servers are
+ * active or down.
+ * - etc.
+ *
+ * Please consult PJLIB-UTIL DNS resolver documentation for more details.
+ *
+ *
+ * \section PJSIP_RESOLVE_USING Using the Resolver
+ *
+ * To maintain backward compatibility, the resolver MUST be enabled manually.
+ * With the default settings, the resolver WILL NOT perform DNS SRV resolution,
+ * as it will just resolve the name with standard pj_gethostbyname() function.
+ *
+ * Application can enable the SRV resolver by creating the PJLIB-UTIL DNS
+ * resolver with #pjsip_endpt_create_resolver(), configure the
+ * nameservers of the PJLIB-UTIL DNS resolver object by calling
+ * pj_dns_resolver_set_ns() function, and pass the DNS resolver object to
+ * #pjsip_resolver_set_resolver() function.
+ *
+ * Once the resolver is set, it will be used automatically by PJSIP everytime
+ * PJSIP needs to send SIP request/response messages.
+ *
+ *
+ * \section PJSIP_RESOLVE_REFERENCE Reference
+ *
+ * Reference:
+ * - RFC 2782: A DNS RR for specifying the location of services (DNS SRV)
+ * - RFC 3263: Locating SIP Servers
*/
-/**
- * Maximum number of addresses returned by the resolver.
- */
-#define PJSIP_MAX_RESOLVED_ADDRESSES 8
-
/**
* The server addresses returned by the resolver.
*/
@@ -61,6 +176,12 @@ typedef struct pjsip_server_addresses
/** Preferable transport to be used to contact this address. */
pjsip_transport_type_e type;
+ /** Server priority (the lower the higher the priority). */
+ unsigned priority;
+
+ /** Server weight (the higher the more load it can handle). */
+ unsigned weight;
+
/** The server's address. */
pj_sockaddr addr;
@@ -85,15 +206,56 @@ typedef void pjsip_resolver_callback(pj_status_t status,
const struct pjsip_server_addresses *addr);
/**
- * Create resolver engine.
+ * Create SIP resolver engine. Note that this function is normally called
+ * internally by pjsip_endpoint instance.
+ *
+ * @param pf The Pool Factory.
+ * @param p_res Pointer to receive SIP resolver instance.
+ *
+ * @return PJ_SUCCESS when resolver can be successfully created.
+ */
+PJ_DECL(pj_status_t) pjsip_resolver_create(pj_pool_t *pool,
+ pjsip_resolver_t **p_res);
+
+/**
+ * Set the DNS resolver instance of the SIP resolver engine. Before the
+ * DNS resolver is set, the SIP resolver will use standard pj_gethostbyname()
+ * to resolve addresses.
*
- * @param pool The Pool.
- * @return The resolver engine.
+ * Note that application normally will use #pjsip_endpt_set_resolver() instead
+ * since it does not normally have access to the SIP resolver instance.
+ *
+ * @param res The SIP resolver engine.
+ * @param dns_res The DNS resolver instance to be used by the SIP resolver.
+ * This argument can be NULL to reset the internal DNS
+ * instance.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsip_resolver_set_resolver(pjsip_resolver_t *res,
+ pj_dns_resolver *dns_res);
+
+
+/**
+ * Get the DNS resolver instance of the SIP resolver engine.
+ *
+ * Note that application normally will use #pjsip_endpt_get_resolver() instead
+ * since it does not normally have access to the SIP resolver instance.
+ *
+ * @param res The SIP resolver engine.
+ *
+ * @return The DNS resolver instance (may be NULL)
*/
-PJ_DECL(pjsip_resolver_t*) pjsip_resolver_create(pj_pool_t *pool);
+PJ_DECL(pj_dns_resolver*) pjsip_resolver_get_resolver(pjsip_resolver_t *res);
/**
- * Destroy resolver engine.
+ * Destroy resolver engine. Note that this will also destroy the internal
+ * DNS resolver inside the engine. If application doesn't want the internal
+ * DNS resolver to be destroyed, it should set the internal DNS resolver
+ * to NULL before calling this function.
+ *
+ * Note that this function will normally called by the SIP endpoint instance
+ * when the SIP endpoint instance is destroyed.
*
* @param resolver The resolver.
*/
@@ -104,7 +266,8 @@ PJ_DECL(void) pjsip_resolver_destroy(pjsip_resolver_t *resolver);
* specified in RFC 3263 (Locating SIP Servers). When the resolving operation
* has completed, the callback will be called.
*
- * Note: at the moment we don't have implementation of RFC 3263 yet!
+ * Note that application normally will use #pjsip_endpt_resolve() instead
+ * since it does not normally have access to the SIP resolver instance.
*
* @param resolver The resolver engine.
* @param pool The pool to allocate resolver job.
@@ -114,7 +277,7 @@ PJ_DECL(void) pjsip_resolver_destroy(pjsip_resolver_t *resolver);
*/
PJ_DECL(void) pjsip_resolve( pjsip_resolver_t *resolver,
pj_pool_t *pool,
- pjsip_host_info *target,
+ const pjsip_host_info *target,
void *token,
pjsip_resolver_callback *cb);
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index 9ded3f15..2b11df01 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -388,6 +388,20 @@ typedef struct pjsua_config
unsigned thread_cnt;
/**
+ * Number of nameservers. If no name server is configured, the SIP SRV
+ * resolution would be disabled, and domain will be resolved with
+ * standard pj_gethostbyname() function.
+ */
+ unsigned nameserver_count;
+
+ /**
+ * Array of nameservers to be used by the SIP resolver subsystem.
+ * The order of the name server specifies the priority (first name
+ * server will be used first, unless it is not reachable).
+ */
+ pj_str_t nameserver[4];
+
+ /**
* Number of outbound proxies in the array.
*/
unsigned outbound_proxy_cnt;
diff --git a/pjsip/src/pjsip/sip_endpoint.c b/pjsip/src/pjsip/sip_endpoint.c
index 1fa39831..571ee11c 100644
--- a/pjsip/src/pjsip/sip_endpoint.c
+++ b/pjsip/src/pjsip/sip_endpoint.c
@@ -484,8 +484,8 @@ PJ_DEF(pj_status_t) pjsip_endpt_create(pj_pool_factory *pf,
}
/* Create asynchronous DNS resolver. */
- endpt->resolver = pjsip_resolver_create(endpt->pool);
- if (!endpt->resolver) {
+ status = pjsip_resolver_create(endpt->pool, &endpt->resolver);
+ if (status != PJ_SUCCESS) {
PJ_LOG(4, (THIS_FILE, "Error creating resolver instance"));
goto on_error;
}
@@ -926,6 +926,42 @@ PJ_DEF(pj_status_t) pjsip_endpt_create_tdata( pjsip_endpoint *endpt,
}
/*
+ * Create the DNS resolver instance.
+ */
+PJ_DEF(pj_status_t) pjsip_endpt_create_resolver(pjsip_endpoint *endpt,
+ pj_dns_resolver **p_resv)
+{
+#if PJSIP_HAS_RESOLVER
+ PJ_ASSERT_RETURN(endpt && p_resv, PJ_EINVAL);
+ return pj_dns_resolver_create( endpt->pf, NULL, 0, endpt->timer_heap,
+ endpt->ioqueue, p_resv);
+#else
+ PJ_UNUSED_ARG(endpt);
+ PJ_UNUSED_ARG(p_resv);
+ pj_assert(!"Resolver is disabled (PJSIP_HAS_RESOLVER==0)");
+ return PJ_EINVALIDOP;
+#endif
+}
+
+/*
+ * Set DNS resolver to be used by the SIP resolver.
+ */
+PJ_DEF(pj_status_t) pjsip_endpt_set_resolver( pjsip_endpoint *endpt,
+ pj_dns_resolver *resv)
+{
+ return pjsip_resolver_set_resolver(endpt->resolver, resv);
+}
+
+/*
+ * Get the DNS resolver being used by the SIP resolver.
+ */
+PJ_DEF(pj_dns_resolver*) pjsip_endpt_get_resolver(pjsip_endpoint *endpt)
+{
+ PJ_ASSERT_RETURN(endpt, NULL);
+ return pjsip_resolver_get_resolver(endpt->resolver);
+}
+
+/*
* Resolve
*/
PJ_DEF(void) pjsip_endpt_resolve( pjsip_endpoint *endpt,
@@ -1036,6 +1072,13 @@ PJ_DEF(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail )
pj_pool_get_capacity(endpt->pool),
pj_pool_get_used_size(endpt->pool)));
+ /* Resolver */
+#if PJSIP_HAS_RESOLVER
+ if (pjsip_endpt_get_resolver(endpt)) {
+ pj_dns_resolver_dump(pjsip_endpt_get_resolver(endpt), detail);
+ }
+#endif
+
/* Transports.
*/
pjsip_tpmgr_dump_transports( endpt->transport_mgr );
diff --git a/pjsip/src/pjsip/sip_resolve.c b/pjsip/src/pjsip/sip_resolve.c
index 5b920be5..8f28f9e8 100644
--- a/pjsip/src/pjsip/sip_resolve.c
+++ b/pjsip/src/pjsip/sip_resolve.c
@@ -19,30 +19,141 @@
#include <pjsip/sip_resolve.h>
#include <pjsip/sip_transport.h>
#include <pjsip/sip_errno.h>
-#include <pj/pool.h>
-#include <pj/ctype.h>
+#include <pjlib-util/errno.h>
+#include <pj/array.h>
#include <pj/assert.h>
+#include <pj/ctype.h>
#include <pj/log.h>
+#include <pj/pool.h>
+#include <pj/rand.h>
+#include <pj/string.h>
+
#define THIS_FILE "sip_resolve.c"
+#define ADDR_MAX_COUNT 8
+
+struct naptr_target
+{
+ pj_str_t target_name; /**< NAPTR target name. */
+ pjsip_transport_type_e type; /**< Transport type. */
+ unsigned order; /**< Order */
+ unsigned pref; /**< Preference. */
+};
+
+struct srv_target
+{
+ pjsip_transport_type_e type;
+ pj_str_t target_name;
+ char target_buf[PJ_MAX_HOSTNAME];
+ unsigned port;
+ unsigned priority;
+ unsigned weight;
+ unsigned sum;
+ unsigned addr_cnt;
+ pj_in_addr addr[ADDR_MAX_COUNT];
+};
+
+struct query
+{
+ char objname[PJ_MAX_OBJ_NAME];
+
+ pjsip_resolver_t *resolver; /**< Resolver SIP instance. */
+ pj_dns_type dns_state; /**< DNS type being resolved. */
+ void *token;
+ pjsip_resolver_callback *cb;
+ pj_dns_async_query *object;
+ pj_status_t last_error;
+
+ /* Original request: */
+ struct {
+ pjsip_host_info target;
+ } req;
+
+ /* NAPTR records: */
+ unsigned naptr_cnt;
+ struct naptr_target naptr[8];
+
+ /* SRV records and their resolved IP addresses: */
+ unsigned srv_cnt;
+ struct srv_target srv[PJSIP_MAX_RESOLVED_ADDRESSES];
+
+ /* Number of hosts in SRV records that the IP address has been resolved */
+ unsigned host_resolved;
+};
+
+
struct pjsip_resolver_t
{
- void *dummy;
+ pj_dns_resolver *res;
+ unsigned job_id;
};
-PJ_DEF(pjsip_resolver_t*) pjsip_resolver_create(pj_pool_t *pool)
+static void dns_callback(void *user_data,
+ pj_status_t status,
+ pj_dns_parsed_packet *response);
+
+
+/*
+ * Public API to create the resolver.
+ */
+PJ_DEF(pj_status_t) pjsip_resolver_create( pj_pool_t *pool,
+ pjsip_resolver_t **p_res)
{
pjsip_resolver_t *resolver;
- resolver = (pjsip_resolver_t*) pj_pool_calloc(pool, 1, sizeof(*resolver));
- return resolver;
+
+ PJ_ASSERT_RETURN(pool && p_res, PJ_EINVAL);
+ resolver = pj_pool_zalloc(pool, sizeof(*resolver));
+ *p_res = resolver;
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Public API to set the DNS resolver instance for the SIP resolver.
+ */
+PJ_DEF(pj_status_t) pjsip_resolver_set_resolver(pjsip_resolver_t *res,
+ pj_dns_resolver *dns_res)
+{
+#if PJSIP_HAS_RESOLVER
+ res->res = dns_res;
+ return PJ_SUCCESS;
+#else
+ PJ_UNUSED_ARG(res);
+ PJ_UNUSED_ARG(dns_res);
+ pj_assert(!"Resolver is disabled (PJSIP_HAS_RESOLVER==0)");
+ return PJ_EINVALIDOP;
+#endif;
+}
+
+
+/*
+ * Public API to get the internal DNS resolver.
+ */
+PJ_DEF(pj_dns_resolver*) pjsip_resolver_get_resolver(pjsip_resolver_t *res)
+{
+ return res->res;
}
+
+/*
+ * Public API to create destroy the resolver
+ */
PJ_DEF(void) pjsip_resolver_destroy(pjsip_resolver_t *resolver)
{
- PJ_UNUSED_ARG(resolver);
+ if (resolver->res) {
+#if PJSIP_HAS_RESOLVER
+ pj_dns_resolver_destroy(resolver->res, PJ_FALSE);
+#endif
+ resolver->res = NULL;
+ }
}
+/*
+ * Internal:
+ * determine if an address is a valid IP address.
+ */
static int is_str_ip(const pj_str_t *host)
{
const char *p = host->ptr;
@@ -58,29 +169,23 @@ static int is_str_ip(const pj_str_t *host)
return 1;
}
+
+/*
+ * This is the main function for performing server resolution.
+ */
PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver,
pj_pool_t *pool,
- pjsip_host_info *target,
+ const pjsip_host_info *target,
void *token,
pjsip_resolver_callback *cb)
{
- struct pjsip_server_addresses svr_addr;
- pj_status_t status;
+ pjsip_server_addresses svr_addr;
+ pj_status_t status = PJ_SUCCESS;
int is_ip_addr;
+ struct query *query;
+ pj_str_t srv_name;
pjsip_transport_type_e type = target->type;
- PJ_UNUSED_ARG(resolver);
- PJ_UNUSED_ARG(pool);
-
- PJ_LOG(5,(THIS_FILE, "Resolving server '%.*s:%d' type=%s",
- target->addr.host.slen,
- target->addr.host.ptr,
- target->addr.port,
- pjsip_transport_get_type_name(type)));
-
- /* We only do synchronous resolving at this moment. */
- PJ_TODO(SUPPORT_RFC3263_SERVER_RESOLUTION)
-
/* Is it IP address or hostname?. */
is_ip_addr = is_str_ip(&target->addr.host);
@@ -109,50 +214,693 @@ PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver,
*/
type = PJSIP_TRANSPORT_UDP;
}
+ }
+
+
+ /* If target is an IP address, or if resolver is not configured,
+ * we can just finish the resolution now using pj_gethostbyname()
+ */
+ if (is_ip_addr || resolver->res == NULL) {
+
+ pj_in_addr ip_addr;
+ pj_uint16_t srv_port;
+
+ if (!is_ip_addr) {
+ PJ_LOG(5,(THIS_FILE,
+ "DNS resolver not available, target '%.*s:%d' type=%s "
+ "will be resolved with gethostbyname()",
+ target->addr.host.slen,
+ target->addr.host.ptr,
+ target->addr.port,
+ pjsip_transport_get_type_name(target->type)));
+ }
+
+ /* Set the port number if not specified. */
+ if (target->addr.port == 0) {
+ srv_port = (pj_uint16_t)
+ pjsip_transport_get_default_port_for_type(type);
+ } else {
+ srv_port = (pj_uint16_t)target->addr.port;
+ }
+
+ /* This will eventually call pj_gethostbyname() if the host
+ * is not an IP address.
+ */
+ status = pj_sockaddr_in_init((pj_sockaddr_in*)&svr_addr.entry[0].addr,
+ &target->addr.host, srv_port);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Call the callback. */
+ ip_addr = ((pj_sockaddr_in*)&svr_addr.entry[0].addr)->sin_addr;
+ PJ_LOG(5,(THIS_FILE,
+ "Target '%.*s:%d' type=%s resolved to "
+ "'%s:%d' type=%s",
+ (int)target->addr.host.slen,
+ target->addr.host.ptr,
+ target->addr.port,
+ pjsip_transport_get_type_name(target->type),
+ pj_inet_ntoa(ip_addr),
+ srv_port,
+ pjsip_transport_get_type_name(type)));
+ svr_addr.count = 1;
+ svr_addr.entry[0].priority = 0;
+ svr_addr.entry[0].weight = 0;
+ svr_addr.entry[0].type = type;
+ svr_addr.entry[0].addr_len = sizeof(pj_sockaddr_in);
+ (*cb)(status, token, &svr_addr);
+ /* Done. */
+ return;
}
- /* Set the port number if not specified. */
- if (target->addr.port == 0) {
- target->addr.port = pjsip_transport_get_default_port_for_type(type);
+ /* Target is not an IP address so we need to resolve it. */
+#if PJSIP_HAS_RESOLVER
+
+ /* Build the query state */
+ query = pj_pool_zalloc(pool, sizeof(struct query));
+ pj_ansi_snprintf(query->objname, sizeof(query->objname), "rsvjob%X",
+ resolver->job_id++);
+ query->resolver = resolver;
+ query->token = token;
+ query->cb = cb;
+ query->req.target = *target;
+ pj_strdup(pool, &query->req.target.addr.host, &target->addr.host);
+
+ /* If port is not specified, start with SRV resolution
+ * (should be with NAPTR, but we'll do that later)
+ */
+ PJ_TODO(SUPPORT_DNS_NAPTR);
+
+ /* Build dummy NAPTR entry */
+ query->naptr_cnt = 1;
+ pj_bzero(&query->naptr[0], sizeof(query->naptr[0]));
+ query->naptr[0].order = 0;
+ query->naptr[0].pref = 0;
+ query->naptr[0].type = type;
+ query->naptr[0].target_name.ptr =
+ pj_pool_alloc(pool, target->addr.host.slen + 12);
+
+ if (type == PJSIP_TRANSPORT_TLS)
+ pj_strcpy2(&query->naptr[0].target_name, "_sips._tcp.");
+ else if (type == PJSIP_TRANSPORT_TCP)
+ pj_strcpy2(&query->naptr[0].target_name, "_sip._tcp.");
+ else if (type == PJSIP_TRANSPORT_UDP)
+ pj_strcpy2(&query->naptr[0].target_name, "_sip._udp.");
+ else {
+ pj_assert(!"Unknown transport type");
+ pj_strcpy2(&query->naptr[0].target_name, "_sip._udp.");
}
+ pj_strcat(&query->naptr[0].target_name, &target->addr.host);
+
+
+ /* Start DNS SRV or A resolution, depending on whether port is specified */
+ if (target->addr.port == 0) {
+ query->dns_state = PJ_DNS_TYPE_SRV;
+ srv_name = query->naptr[0].target_name;
- /* Resolve hostname. */
- if (!is_ip_addr) {
- status = pj_sockaddr_in_init((pj_sockaddr_in*)&svr_addr.entry[0].addr,
- &target->addr.host,
- (pj_uint16_t)target->addr.port);
} else {
- status = pj_sockaddr_in_init((pj_sockaddr_in*)&svr_addr.entry[0].addr,
- &target->addr.host,
- (pj_uint16_t)target->addr.port);
+ /* Otherwise if port is specified, start with A (or AAAA) host
+ * resolution
+ */
+ query->dns_state = PJ_DNS_TYPE_A;
+
+ /* Since we don't perform SRV resolution, pretend that we'ee already
+ * done so by inserting a dummy SRV record.
+ */
+
+ query->srv_cnt = 1;
+ pj_bzero(&query->srv[0], sizeof(query->srv[0]));
+ query->srv[0].target_name = query->req.target.addr.host;
+ query->srv[0].type = type;
+ query->srv[0].port = query->req.target.addr.port;
+ query->srv[0].priority = 0;
+ query->srv[0].weight = 0;
+
+ srv_name = query->srv[0].target_name;
}
+ /* Start the asynchronous query */
+ PJ_LOG(5, (query->objname,
+ "Starting async DNS %s query: target=%.*s, transport=%s, "
+ "port=%d",
+ pj_dns_get_type_name(query->dns_state),
+ (int)srv_name.slen, srv_name.ptr,
+ pjsip_transport_get_type_name(target->type),
+ target->addr.port));
+
+ status = pj_dns_resolver_start_query(resolver->res, &srv_name,
+ query->dns_state, 0, &dns_callback,
+ query, &query->object);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ return;
+
+#else /* PJSIP_HAS_RESOLVER */
+ PJ_UNUSED_ARG(pool);
+ PJ_UNUSED_ARG(query);
+ PJ_UNUSED_ARG(srv_name);
+#endif /* PJSIP_HAS_RESOLVER */
+
+on_error:
if (status != PJ_SUCCESS) {
char errmsg[PJ_ERR_MSG_SIZE];
PJ_LOG(4,(THIS_FILE, "Failed to resolve '%.*s'. Err=%d (%s)",
- target->addr.host.slen,
+ (int)target->addr.host.slen,
target->addr.host.ptr,
status,
pj_strerror(status,errmsg,sizeof(errmsg)).ptr));
- (*cb)(status, token, &svr_addr);
+ (*cb)(status, token, NULL);
+ return;
+ }
+}
+
+/*
+ * The rest of the code should only get compiled when resolver is enabled
+ */
+#if PJSIP_HAS_RESOLVER
+
+#define SWAP(type,ptr1,ptr2) if (ptr1 != ptr2) { \
+ type tmp; \
+ pj_memcpy(&tmp, ptr1, sizeof(type)); \
+ pj_memcpy(ptr1, ptr2, sizeof(type)); \
+ (ptr1)->target_name.ptr = (ptr1)->target_buf; \
+ pj_memcpy(ptr2, &tmp, sizeof(type)); \
+ (ptr2)->target_name.ptr = (ptr2)->target_buf; \
+ } else {}
+
+/* Build server entries in the query based on received SRV response */
+static void build_server_entries(struct query *query,
+ pj_dns_parsed_packet *response)
+{
+ unsigned i;
+ unsigned naptr_id;
+
+ /* Find NAPTR target which corresponds to this SRV target */
+ for (naptr_id=0; naptr_id < query->naptr_cnt; ++naptr_id) {
+ if (pj_stricmp(&query->naptr[naptr_id].target_name,
+ &response->ans[0].name)==0)
+ break;
+ }
+ if (naptr_id == query->naptr_cnt) {
+ PJ_LOG(4,(query->objname,
+ "Unable to find NAPTR record for SRV name %.*s!",
+ (int)response->ans[0].name.slen,
+ response->ans[0].name.ptr));
return;
}
- /* Call the callback. */
- PJ_LOG(5,(THIS_FILE, "Server resolved: '%.*s:%d' type=%s has %d entries, "
- "entry[0]=%s:%d type=%s",
- target->addr.host.slen,
- target->addr.host.ptr,
- target->addr.port,
- pjsip_transport_get_type_name(type),
- 1,
- pj_inet_ntoa(((pj_sockaddr_in*)&svr_addr.entry[0].addr)->sin_addr),
- target->addr.port,
- pjsip_transport_get_type_name(type)));
- svr_addr.count = (status == PJ_SUCCESS) ? 1 : 0;
- svr_addr.entry[0].type = type;
- svr_addr.entry[0].addr_len = sizeof(pj_sockaddr_in);
- (*cb)(status, token, &svr_addr);
+
+ /* Save the Resource Records in DNS answer into SRV targets. */
+ query->srv_cnt = 0;
+ for (i=0; i<response->hdr.anscount &&
+ query->srv_cnt < PJSIP_MAX_RESOLVED_ADDRESSES; ++i)
+ {
+ pj_dns_parsed_rr *rr = &response->ans[i];
+ struct srv_target *srv = &query->srv[query->srv_cnt];
+
+ if (rr->type != PJ_DNS_TYPE_SRV) {
+ PJ_LOG(4,(query->objname,
+ "Received non SRV answer for SRV query!"));
+ continue;
+ }
+
+ if (rr->rdata.srv.target.slen > PJ_MAX_HOSTNAME) {
+ PJ_LOG(4,(query->objname, "Hostname is too long!"));
+ continue;
+ }
+
+ /* Build the SRV entry for RR */
+ pj_bzero(srv, sizeof(*srv));
+ pj_memcpy(srv->target_buf, rr->rdata.srv.target.ptr,
+ rr->rdata.srv.target.slen);
+ srv->target_name.ptr = srv->target_buf;
+ srv->target_name.slen = rr->rdata.srv.target.slen;
+ srv->type = query->naptr[naptr_id].type;
+ srv->port = rr->rdata.srv.port;
+ srv->priority = rr->rdata.srv.prio;
+ srv->weight = rr->rdata.srv.weight;
+
+ ++query->srv_cnt;
+ }
+
+ /* First pass:
+ * order the entries based on priority.
+ */
+ for (i=0; i<query->srv_cnt-1; ++i) {
+ unsigned min = i, j;
+ for (j=i+1; j<query->srv_cnt; ++j) {
+ if (query->srv[j].priority < query->srv[min].priority)
+ min = j;
+ }
+ SWAP(struct srv_target, &query->srv[i], &query->srv[min]);
+ }
+
+ /* Second pass:
+ * pick one host among hosts with the same priority, according
+ * to its weight. The idea is when one server fails, client should
+ * contact the next server with higher priority rather than contacting
+ * server with the same priority as the failed one.
+ *
+ * The algorithm for selecting server among servers with the same
+ * priority is described in RFC 2782.
+ */
+ for (i=0; i<query->srv_cnt; ++i) {
+ unsigned j, count=1, sum;
+
+ /* Calculate running sum for servers with the same priority */
+ sum = query->srv[i].sum = query->srv[i].weight;
+ for (j=i+1; j<query->srv_cnt &&
+ query->srv[j].priority == query->srv[i].priority; ++j)
+ {
+ sum += query->srv[j].weight;
+ query->srv[j].sum = sum;
+ ++count;
+ }
+
+ if (count > 1) {
+ unsigned r;
+
+ /* Elect one random number between zero and the total sum of
+ * weight (inclusive).
+ */
+ r = pj_rand() % (sum + 1);
+
+ /* Select the first server which running sum is greater than or
+ * equal to the random number.
+ */
+ for (j=i; j<i+count; ++j) {
+ if (query->srv[j].sum >= r)
+ break;
+ }
+
+ /* Must have selected one! */
+ pj_assert(j != i+count);
+
+ /* Put this entry in front (of entries with same priority) */
+ SWAP(struct srv_target, &query->srv[i], &query->srv[j]);
+
+ /* Remove all other entries (of the same priority) */
+ while (count > 1) {
+ pj_array_erase(query->srv, sizeof(struct srv_target),
+ query->srv_cnt, i+1);
+ --count;
+ --query->srv_cnt;
+ }
+ }
+ }
+
+ /* Since we've been moving around SRV entries, update the pointers
+ * in target_name.
+ */
+ for (i=0; i<query->srv_cnt; ++i) {
+ query->srv[i].target_name.ptr = query->srv[i].target_buf;
+ }
+
+ /* Check for Additional Info section if A records are available, and
+ * fill in the IP address (so that we won't need to resolve the A
+ * record with another DNS query).
+ */
+ for (i=0; i<response->hdr.arcount; ++i) {
+ pj_dns_parsed_rr *rr = &response->arr[i];
+ unsigned j;
+
+ if (rr->type != PJ_DNS_TYPE_A)
+ continue;
+
+ /* Yippeaiyee!! There is an "A" record!
+ * Update the IP address of the corresponding SRV record.
+ */
+ for (j=0; j<query->srv_cnt; ++j) {
+ if (pj_stricmp(&rr->name, &query->srv[j].target_name)==0) {
+ unsigned cnt = query->srv[j].addr_cnt;
+ query->srv[j].addr[cnt] = pj_inet_addr(&rr->rdata.a.ip_addr);
+ ++query->srv[j].addr_cnt;
+ ++query->host_resolved;
+ break;
+ }
+ }
+
+ /* Not valid message; SRV entry might have been deleted in
+ * server selection process.
+ */
+ /*
+ if (j == query->srv_cnt) {
+ PJ_LOG(4,(query->objname,
+ "Received DNS SRV answer with A record, but "
+ "couldn't find matching name (name=%.*s)",
+ (int)rr->name.slen,
+ rr->name.ptr));
+ }
+ */
+ }
+
+ /* Rescan again the name specified in the SRV record to see if IP
+ * address is specified as the target name (unlikely, but well, who
+ * knows..).
+ */
+ for (i=0; i<query->srv_cnt; ++i) {
+ pj_in_addr addr;
+
+ if (query->srv[i].addr_cnt != 0) {
+ /* IP address already resolved */
+ continue;
+ }
+
+ if (pj_inet_aton(&query->srv[i].target_name, &addr) != 0) {
+ query->srv[i].addr[query->srv[i].addr_cnt++] = addr;
+ ++query->host_resolved;
+ }
+ }
+
+ /* Print resolved entries to the log */
+ PJ_LOG(5,(query->objname,
+ "SRV query for %.*s completed, "
+ "%d of %d total entries selected%c",
+ (int)query->naptr[naptr_id].target_name.slen,
+ query->naptr[naptr_id].target_name.ptr,
+ query->srv_cnt,
+ response->hdr.anscount,
+ (query->srv_cnt ? ':' : ' ')));
+
+ for (i=0; i<query->srv_cnt; ++i) {
+ const char *addr;
+
+ if (query->srv[i].addr_cnt != 0)
+ addr = pj_inet_ntoa(query->srv[i].addr[0]);
+ else
+ addr = "-";
+
+ PJ_LOG(5,(query->objname,
+ " %d: SRV %d %d %d %.*s (%s)",
+ i, query->srv[i].priority,
+ query->srv[i].weight,
+ query->srv[i].port,
+ (int)query->srv[i].target_name.slen,
+ query->srv[i].target_name.ptr,
+ addr));
+ }
}
+
+/* Start DNS A record queries for all SRV records in the query structure */
+static pj_status_t resolve_hostnames(struct query *query)
+{
+ unsigned i;
+ pj_status_t err=PJ_SUCCESS, status;
+
+ query->dns_state = PJ_DNS_TYPE_A;
+ for (i=0; i<query->srv_cnt; ++i) {
+ PJ_LOG(5, (query->objname,
+ "Starting async DNS A query for %.*s",
+ (int)query->srv[i].target_name.slen,
+ query->srv[i].target_name.ptr));
+
+ status = pj_dns_resolver_start_query(query->resolver->res,
+ &query->srv[i].target_name,
+ PJ_DNS_TYPE_A, 0,
+ &dns_callback,
+ query, NULL);
+ if (status != PJ_SUCCESS) {
+ query->host_resolved++;
+ err = status;
+ }
+ }
+
+ return (query->host_resolved == query->srv_cnt) ? err : PJ_SUCCESS;
+}
+
+/*
+ * This callback is called by PJLIB-UTIL DNS resolver when asynchronous
+ * query has completed (successfully or with error).
+ */
+static void dns_callback(void *user_data,
+ pj_status_t status,
+ pj_dns_parsed_packet *pkt)
+{
+ struct query *query = user_data;
+ unsigned i;
+
+ /* Proceed to next stage */
+
+ if (query->dns_state == PJ_DNS_TYPE_SRV) {
+
+ /* We are getting SRV response */
+
+ if (status == PJ_SUCCESS && pkt->hdr.anscount != 0) {
+ /* Got SRV response, build server entry. If A records are available
+ * in additional records section of the DNS response, save them too.
+ */
+ build_server_entries(query, pkt);
+
+ } else if (status != PJ_SUCCESS) {
+ char errmsg[PJ_ERR_MSG_SIZE];
+ unsigned naptr_id;
+
+ /* Update query last error */
+ query->last_error = status;
+
+ /* Find which NAPTR target has not got SRV records */
+ for (naptr_id=0; naptr_id < query->naptr_cnt; ++naptr_id) {
+ for (i=0; i<query->srv_cnt; ++i) {
+ if (query->srv[i].type == query->naptr[naptr_id].type)
+ break;
+ }
+ if (i == query->srv_cnt)
+ break;
+ }
+ if (naptr_id == query->naptr_cnt) {
+ /* Strangely all NAPTR records seem to already have SRV
+ * records! This is quite unexpected, by anyway lets set
+ * the naptr_id to zero just in case.
+ */
+ pj_assert(!"Strange");
+ naptr_id = 0;
+
+ }
+
+ pj_strerror(status, errmsg, sizeof(errmsg));
+ PJ_LOG(4,(query->objname,
+ "DNS SRV resolution failed for %.*s: %s",
+ (int)query->naptr[naptr_id].target_name.slen,
+ query->naptr[naptr_id].target_name.ptr,
+ errmsg));
+ }
+
+ /* If we can't build SRV record, assume the original target is
+ * an A record.
+ */
+ if (query->srv_cnt == 0) {
+ /* Looks like we aren't getting any SRV responses.
+ * Resolve the original target as A record by creating a
+ * single "dummy" srv record and start the hostname resolution.
+ */
+ unsigned naptr_id;
+
+ /* Find which NAPTR target has not got SRV records */
+ for (naptr_id=0; naptr_id < query->naptr_cnt; ++naptr_id) {
+ for (i=0; i<query->srv_cnt; ++i) {
+ if (query->srv[i].type == query->naptr[naptr_id].type)
+ break;
+ }
+ if (i == query->srv_cnt)
+ break;
+ }
+ if (naptr_id == query->naptr_cnt) {
+ /* Strangely all NAPTR records seem to already have SRV
+ * records! This is quite unexpected, by anyway lets set
+ * the naptr_id to zero just in case.
+ */
+ pj_assert(!"Strange");
+ naptr_id = 0;
+
+ }
+
+ PJ_LOG(4, (query->objname,
+ "DNS SRV resolution failed for %.*s, trying "
+ "resolving A record for %.*s",
+ (int)query->naptr[naptr_id].target_name.slen,
+ query->naptr[naptr_id].target_name.ptr,
+ (int)query->req.target.addr.host.slen,
+ query->req.target.addr.host.ptr));
+
+ /* Create a "dummy" srv record using the original target */
+ i = query->srv_cnt++;
+ pj_bzero(&query->srv[i], sizeof(query->srv[i]));
+ query->srv[i].target_name = query->req.target.addr.host;
+ query->srv[i].type = query->naptr[naptr_id].type;
+ query->srv[i].priority = 0;
+ query->srv[i].weight = 0;
+
+ query->srv[i].port = query->req.target.addr.port;
+ if (query->srv[i].port == 0) {
+ query->srv[i].port = (pj_uint16_t)
+ pjsip_transport_get_default_port_for_type(query->srv[i].type);
+ }
+ }
+
+
+ /* Resolve server hostnames (DNS A record) for hosts which don't have
+ * A record yet.
+ */
+ if (query->host_resolved != query->srv_cnt) {
+ status = resolve_hostnames(query);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Must return now. Callback may have been called and query
+ * may have been destroyed.
+ */
+ return;
+ }
+
+ } else if (query->dns_state == PJ_DNS_TYPE_A) {
+
+ /* Check that we really have answer */
+ if (status==PJ_SUCCESS && pkt->hdr.anscount != 0) {
+
+ /* Update IP address of the corresponding hostname */
+ for (i=0; i<query->srv_cnt; ++i) {
+ if (pj_stricmp(&pkt->ans[0].name,
+ &query->srv[i].target_name)==0)
+ {
+ break;
+ }
+ }
+
+ if (i == query->srv_cnt) {
+ PJ_LOG(4,(query->objname,
+ "Received answer to DNS A request with no matching "
+ "SRV record! The unknown name is %.*s",
+ (int)pkt->ans[0].name.slen, pkt->ans[0].name.ptr));
+ } else {
+ unsigned j;
+
+ query->srv[i].addr[query->srv[i].addr_cnt++] =
+ pj_inet_addr(&pkt->ans[0].rdata.a.ip_addr);
+
+ PJ_LOG(5,(query->objname,
+ "DNS A for %.*s: %.*s",
+ (int)query->srv[i].target_name.slen,
+ query->srv[i].target_name.ptr,
+ (int)pkt->ans[0].rdata.a.ip_addr.slen,
+ pkt->ans[0].rdata.a.ip_addr.ptr));
+
+ /* Check for multiple IP addresses */
+ for (j=1; j<pkt->hdr.anscount &&
+ query->srv[i].addr_cnt < ADDR_MAX_COUNT; ++j)
+ {
+ query->srv[i].addr[query->srv[i].addr_cnt++] =
+ pj_inet_addr(&pkt->ans[j].rdata.a.ip_addr);
+
+ PJ_LOG(5,(query->objname,
+ "Additional DNS A for %.*s: %.*s",
+ (int)query->srv[i].target_name.slen,
+ query->srv[i].target_name.ptr,
+ (int)pkt->ans[j].rdata.a.ip_addr.slen,
+ pkt->ans[j].rdata.a.ip_addr.ptr));
+ }
+ }
+
+ } else if (status != PJ_SUCCESS) {
+ char errmsg[PJ_ERR_MSG_SIZE];
+
+ /* Update last error */
+ query->last_error = status;
+
+ /* Log error */
+ pj_strerror(status, errmsg, sizeof(errmsg));
+ PJ_LOG(4,(query->objname, "DNS A record resolution failed: %s",
+ errmsg));
+ }
+
+ ++query->host_resolved;
+
+ } else {
+ pj_assert(!"Unexpected state!");
+ query->last_error = status = PJ_EINVALIDOP;
+ goto on_error;
+ }
+
+ /* Check if all hosts have been resolved */
+ if (query->host_resolved == query->srv_cnt) {
+ /* Got all answers, build server addresses */
+ pjsip_server_addresses svr_addr;
+
+ svr_addr.count = 0;
+ for (i=0; i<query->srv_cnt; ++i) {
+ unsigned j;
+
+ /* Do we have IP address for this server? */
+ /* This log is redundant really.
+ if (query->srv[i].addr_cnt == 0) {
+ PJ_LOG(5,(query->objname,
+ " SRV target %.*s:%d does not have IP address!",
+ (int)query->srv[i].target_name.slen,
+ query->srv[i].target_name.ptr,
+ query->srv[i].port));
+ continue;
+ }
+ */
+
+ for (j=0; j<query->srv[i].addr_cnt; ++j) {
+ unsigned idx = svr_addr.count;
+ pj_sockaddr_in *addr;
+
+ svr_addr.entry[idx].type = query->srv[i].type;
+ svr_addr.entry[idx].priority = query->srv[i].priority;
+ svr_addr.entry[idx].weight = query->srv[i].weight;
+ svr_addr.entry[idx].addr_len = sizeof(pj_sockaddr_in);
+
+ addr = (pj_sockaddr_in*)&svr_addr.entry[idx].addr;
+ pj_bzero(addr, sizeof(pj_sockaddr_in));
+ addr->sin_family = PJ_AF_INET;
+ addr->sin_addr = query->srv[i].addr[j];
+ addr->sin_port = pj_htons((pj_uint16_t)query->srv[i].port);
+
+ ++svr_addr.count;
+ }
+ }
+
+ PJ_LOG(5,(query->objname,
+ "Server resolution complete, %d server entry(s) found",
+ svr_addr.count));
+
+
+ if (svr_addr.count > 0)
+ status = PJ_SUCCESS;
+ else {
+ status = query->last_error;
+ if (status == PJ_SUCCESS)
+ status = PJLIB_UTIL_EDNSNOANSWERREC;
+ }
+
+ /* Call the callback */
+ (*query->cb)(status, query->token, &svr_addr);
+ }
+
+
+ return;
+
+on_error:
+ /* Check for failure */
+ if (status != PJ_SUCCESS) {
+ char errmsg[PJ_ERR_MSG_SIZE];
+ PJ_LOG(4,(query->objname,
+ "DNS %s record resolution error for '%.*s'."
+ " Err=%d (%s)",
+ pj_dns_get_type_name(query->dns_state),
+ (int)query->req.target.addr.host.slen,
+ query->req.target.addr.host.ptr,
+ status,
+ pj_strerror(status,errmsg,sizeof(errmsg)).ptr));
+ (*query->cb)(status, query->token, NULL);
+ return;
+ }
+}
+
+#endif /* PJSIP_HAS_RESOLVER */
+
+
+
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index 6b39fdbb..b4f4325f 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -456,6 +456,45 @@ PJ_DEF(pj_status_t) pjsua_init( const pjsua_config *ua_cfg,
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
}
+ /* If nameserver is configured, create DNS resolver instance and
+ * set it to be used by SIP resolver.
+ */
+ if (ua_cfg->nameserver_count) {
+#if PJSIP_HAS_RESOLVER
+ pj_dns_resolver *resv;
+ unsigned i;
+
+ /* Create DNS resolver */
+ status = pjsip_endpt_create_resolver(pjsua_var.endpt, &resv);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+
+ /* Configure nameserver for the DNS resolver */
+ status = pj_dns_resolver_set_ns(resv, ua_cfg->nameserver_count,
+ ua_cfg->nameserver, NULL);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error setting nameserver", status);
+ return status;
+ }
+
+ /* Set this DNS resolver to be used by the SIP resolver */
+ status = pjsip_endpt_set_resolver(pjsua_var.endpt, resv);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error setting DNS resolver", status);
+ return status;
+ }
+
+ /* Print nameservers */
+ for (i=0; i<ua_cfg->nameserver_count; ++i) {
+ PJ_LOG(4,(THIS_FILE, "Nameserver %.*s added",
+ (int)ua_cfg->nameserver[i].slen,
+ ua_cfg->nameserver[i].ptr));
+ }
+#else
+ PJ_LOG(2,(THIS_FILE,
+ "DNS resolver is disabled (PJSIP_HAS_RESOLVER==0)"));
+#endif
+ }
+
/* Init SIP UA: */
/* Initialize transaction layer: */
diff --git a/pjsip/src/test-pjsip/dns_test.c b/pjsip/src/test-pjsip/dns_test.c
new file mode 100644
index 00000000..a088e5d9
--- /dev/null
+++ b/pjsip/src/test-pjsip/dns_test.c
@@ -0,0 +1,596 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2006 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 "test.h"
+#include <pjsip.h>
+#include <pjlib.h>
+#include <pjlib-util.h>
+
+/* For logging purpose. */
+#define THIS_FILE "dns_test.c"
+
+struct result
+{
+ pj_status_t status;
+ pjsip_server_addresses servers;
+};
+
+
+static void cb(pj_status_t status,
+ void *token,
+ const struct pjsip_server_addresses *addr)
+{
+ struct result *result = token;
+
+ result->status = status;
+ if (status == PJ_SUCCESS)
+ pj_memcpy(&result->servers, addr, sizeof(*addr));
+}
+
+
+static void add_dns_entries(pj_dns_resolver *resv)
+{
+ /* Inject DNS SRV entry */
+ pj_dns_parsed_packet pkt;
+ pj_dns_parsed_rr ans[4];
+ pj_dns_parsed_rr ar[5];
+ unsigned i;
+
+ /*
+ * This is answer to SRV query to "example.com" domain, and
+ * the answer contains full reference to the A records of
+ * the server. The full DNS records is :
+
+ _sip._udp.example.com 3600 IN SRV 0 0 5060 sip01.example.com.
+ _sip._udp.example.com 3600 IN SRV 0 20 5060 sip02.example.com.
+ _sip._udp.example.com 3600 IN SRV 0 10 5060 sip03.example.com.
+ _sip._udp.example.com 3600 IN SRV 1 0 5060 sip04.example.com.
+
+ sip01.example.com. 3600 IN A 1.1.1.1
+ sip02.example.com. 3600 IN A 2.2.2.2
+ sip03.example.com. 3600 IN A 3.3.3.3
+ sip04.example.com. 3600 IN A 4.4.4.4
+
+ ; Additionally, add A record for "example.com"
+ example.com. 3600 IN A 5.5.5.5
+
+ */
+ pj_bzero(&pkt, sizeof(pkt));
+ pj_bzero(ans, sizeof(ans));
+ pj_bzero(ar, sizeof(ar));
+
+ pkt.hdr.flags = PJ_DNS_SET_QR(1);
+ pkt.hdr.anscount = PJ_ARRAY_SIZE(ans);
+ pkt.hdr.arcount = 0;
+ pkt.ans = ans;
+ pkt.arr = ar;
+
+ ans[0].name = pj_str("_sip._udp.example.com");
+ ans[0].type = PJ_DNS_TYPE_SRV;
+ ans[0].dnsclass = PJ_DNS_CLASS_IN;
+ ans[0].ttl = 3600;
+ ans[0].rdata.srv.prio = 0;
+ ans[0].rdata.srv.weight = 0;
+ ans[0].rdata.srv.port = 5060;
+ ans[0].rdata.srv.target = pj_str("sip01.example.com");
+
+ ans[1].name = pj_str("_sip._udp.example.com");
+ ans[1].type = PJ_DNS_TYPE_SRV;
+ ans[1].dnsclass = PJ_DNS_CLASS_IN;
+ ans[1].ttl = 3600;
+ ans[1].rdata.srv.prio = 0;
+ ans[1].rdata.srv.weight = 20;
+ ans[1].rdata.srv.port = 5060;
+ ans[1].rdata.srv.target = pj_str("sip02.example.com");
+
+ ans[2].name = pj_str("_sip._udp.example.com");
+ ans[2].type = PJ_DNS_TYPE_SRV;
+ ans[2].dnsclass = PJ_DNS_CLASS_IN;
+ ans[2].ttl = 3600;
+ ans[2].rdata.srv.prio = 0;
+ ans[2].rdata.srv.weight = 10;
+ ans[2].rdata.srv.port = 5060;
+ ans[2].rdata.srv.target = pj_str("sip03.example.com");
+
+ ans[3].name = pj_str("_sip._udp.example.com");
+ ans[3].type = PJ_DNS_TYPE_SRV;
+ ans[3].dnsclass = PJ_DNS_CLASS_IN;
+ ans[3].ttl = 3600;
+ ans[3].rdata.srv.prio = 1;
+ ans[3].rdata.srv.weight = 0;
+ ans[3].rdata.srv.port = 5060;
+ ans[3].rdata.srv.target = pj_str("sip04.example.com");
+
+ pj_dns_resolver_add_entry( resv, &pkt, PJ_FALSE);
+
+ ar[0].name = pj_str("sip01.example.com");
+ ar[0].type = PJ_DNS_TYPE_A;
+ ar[0].dnsclass = PJ_DNS_CLASS_IN;
+ ar[0].ttl = 3600;
+ ar[0].rdata.a.ip_addr = pj_str("1.1.1.1");
+
+ ar[1].name = pj_str("sip02.example.com");
+ ar[1].type = PJ_DNS_TYPE_A;
+ ar[1].dnsclass = PJ_DNS_CLASS_IN;
+ ar[1].ttl = 3600;
+ ar[1].rdata.a.ip_addr = pj_str("2.2.2.2");
+
+ ar[2].name = pj_str("sip03.example.com");
+ ar[2].type = PJ_DNS_TYPE_A;
+ ar[2].dnsclass = PJ_DNS_CLASS_IN;
+ ar[2].ttl = 3600;
+ ar[2].rdata.a.ip_addr = pj_str("3.3.3.3");
+
+ ar[3].name = pj_str("sip04.example.com");
+ ar[3].type = PJ_DNS_TYPE_A;
+ ar[3].dnsclass = PJ_DNS_CLASS_IN;
+ ar[3].ttl = 3600;
+ ar[3].rdata.a.ip_addr = pj_str("4.4.4.4");
+
+ ar[4].name = pj_str("example.com");
+ ar[4].type = PJ_DNS_TYPE_A;
+ ar[4].dnsclass = PJ_DNS_CLASS_IN;
+ ar[4].ttl = 3600;
+ ar[4].rdata.a.ip_addr = pj_str("5.5.5.5");
+
+ /*
+ * Create individual A records for all hosts in "example.com" domain.
+ */
+ for (i=0; i<PJ_ARRAY_SIZE(ar); ++i) {
+ pj_bzero(&pkt, sizeof(pkt));
+ pkt.hdr.anscount = 1;
+ pkt.hdr.flags = PJ_DNS_SET_QR(1);
+ pkt.ans = &ar[i];
+
+ pj_dns_resolver_add_entry( resv, &pkt, PJ_FALSE);
+ }
+
+ /*
+ * Simulate DNS error response by creating these answers.
+ * Sample of invalid SRV records: _sip._udp.sip01.example.com.
+ */
+ for (i=0; i<PJ_ARRAY_SIZE(ans); ++i) {
+ pj_dns_parsed_query q;
+ char buf[128];
+ char *services[] = { "_sip._udp.", "_sip._tcp.", "_sips._tcp."};
+ unsigned j;
+
+ for (j=0; j<PJ_ARRAY_SIZE(services); ++j) {
+ q.dnsclass = PJ_DNS_CLASS_IN;
+ q.type = PJ_DNS_TYPE_SRV;
+
+ q.name.ptr = buf;
+ pj_bzero(buf, sizeof(buf));
+ pj_strcpy2(&q.name, services[j]);
+ pj_strcat(&q.name, &ans[i].rdata.srv.target);
+
+ pj_bzero(&pkt, sizeof(pkt));
+ pkt.hdr.qdcount = 1;
+ pkt.hdr.flags = PJ_DNS_SET_QR(1) |
+ PJ_DNS_SET_RCODE(PJ_DNS_RCODE_NXDOMAIN);
+ pkt.q = &q;
+
+ pj_dns_resolver_add_entry( resv, &pkt, PJ_FALSE);
+ }
+ }
+
+
+ /*
+ * ANOTHER DOMAIN.
+ *
+ * This time we let SRV and A get answered in different DNS
+ * query.
+ */
+
+ /* The "domain.com" DNS records (note the different the port):
+
+ _sip._tcp.domain.com 3600 IN SRV 1 0 50060 sip06.domain.com.
+ _sip._tcp.domain.com 3600 IN SRV 2 0 50060 sip07.domain.com.
+
+ sip06.domain.com. 3600 IN A 6.6.6.6
+ sip07.domain.com. 3600 IN A 7.7.7.7
+ */
+
+ pj_bzero(&pkt, sizeof(pkt));
+ pj_bzero(&ans, sizeof(ans));
+ pkt.hdr.flags = PJ_DNS_SET_QR(1);
+ pkt.hdr.anscount = 2;
+ pkt.ans = ans;
+
+ /* Add the SRV records, with reverse priority (to test that sorting
+ * works.
+ */
+ ans[0].name = pj_str("_sip._tcp.domain.com");
+ ans[0].type = PJ_DNS_TYPE_SRV;
+ ans[0].dnsclass = PJ_DNS_CLASS_IN;
+ ans[0].ttl = 3600;
+ ans[0].rdata.srv.prio = 2;
+ ans[0].rdata.srv.weight = 0;
+ ans[0].rdata.srv.port = 50060;
+ ans[0].rdata.srv.target = pj_str("SIP07.DOMAIN.COM");
+
+ ans[1].name = pj_str("_sip._tcp.domain.com");
+ ans[1].type = PJ_DNS_TYPE_SRV;
+ ans[1].dnsclass = PJ_DNS_CLASS_IN;
+ ans[1].ttl = 3600;
+ ans[1].rdata.srv.prio = 1;
+ ans[1].rdata.srv.weight = 0;
+ ans[1].rdata.srv.port = 50060;
+ ans[1].rdata.srv.target = pj_str("SIP06.DOMAIN.COM");
+
+ pj_dns_resolver_add_entry( resv, &pkt, PJ_FALSE);
+
+ /* From herein there is only one answer */
+ pkt.hdr.anscount = 1;
+
+ /* Add a single SRV for UDP */
+ ans[0].name = pj_str("_sip._udp.domain.com");
+ ans[0].type = PJ_DNS_TYPE_SRV;
+ ans[0].dnsclass = PJ_DNS_CLASS_IN;
+ ans[0].ttl = 3600;
+ ans[0].rdata.srv.prio = 0;
+ ans[0].rdata.srv.weight = 0;
+ ans[0].rdata.srv.port = 50060;
+ ans[0].rdata.srv.target = pj_str("SIP06.DOMAIN.COM");
+
+ pj_dns_resolver_add_entry( resv, &pkt, PJ_FALSE);
+
+
+ /* Add the A record for sip06.domain.com */
+ ans[0].name = pj_str("sip06.domain.com");
+ ans[0].type = PJ_DNS_TYPE_A;
+ ans[0].dnsclass = PJ_DNS_CLASS_IN;
+ ans[0].ttl = 3600;
+ ans[0].rdata.a.ip_addr = pj_str("6.6.6.6");
+
+ pj_dns_resolver_add_entry( resv, &pkt, PJ_FALSE);
+
+ /* Add the A record for sip07.domain.com */
+ ans[0].name = pj_str("sip07.domain.com");
+ ans[0].type = PJ_DNS_TYPE_A;
+ ans[0].dnsclass = PJ_DNS_CLASS_IN;
+ ans[0].ttl = 3600;
+ ans[0].rdata.a.ip_addr = pj_str("7.7.7.7");
+
+ pj_dns_resolver_add_entry( resv, &pkt, PJ_FALSE);
+}
+
+
+/*
+ * Perform server resolution where the results are expected to
+ * come in strict order.
+ */
+static int test_resolve(const char *title,
+ pj_pool_t *pool,
+ pjsip_transport_type_e type,
+ char *name,
+ int port,
+ pjsip_server_addresses *ref)
+{
+ pjsip_host_info dest;
+ struct result result;
+
+ PJ_LOG(3,(THIS_FILE, " test_resolve(): %s", title));
+
+ dest.type = type;
+ dest.flag = pjsip_transport_get_flag_from_type(type);
+ dest.addr.host = pj_str(name);
+ dest.addr.port = port;
+
+ result.status = 0x12345678;
+
+ pjsip_endpt_resolve(endpt, pool, &dest, &result, &cb);
+
+ while (result.status == 0x12345678) {
+ int i = 0;
+ pj_time_val timeout = { 1, 0 };
+ pjsip_endpt_handle_events(endpt, &timeout);
+ if (i == 1)
+ pj_dns_resolver_dump(pjsip_endpt_get_resolver(endpt), PJ_TRUE);
+ }
+
+ if (result.status != PJ_SUCCESS) {
+ app_perror(" pjsip_endpt_resolve() error", result.status);
+ return result.status;
+ }
+
+ if (ref) {
+ unsigned i;
+
+ if (ref->count != result.servers.count) {
+ PJ_LOG(3,(THIS_FILE, " test_resolve() error 10: result count mismatch"));
+ return 10;
+ }
+
+ for (i=0; i<ref->count; ++i) {
+ pj_sockaddr_in *ra = (pj_sockaddr_in *)&ref->entry[i].addr;
+ pj_sockaddr_in *rb = (pj_sockaddr_in *)&result.servers.entry[i].addr;
+
+ if (ra->sin_addr.s_addr != rb->sin_addr.s_addr) {
+ PJ_LOG(3,(THIS_FILE, " test_resolve() error 20: IP address mismatch"));
+ return 20;
+ }
+ if (ra->sin_port != rb->sin_port) {
+ PJ_LOG(3,(THIS_FILE, " test_resolve() error 30: port mismatch"));
+ return 30;
+ }
+ if (ref->entry[i].addr_len != result.servers.entry[i].addr_len) {
+ PJ_LOG(3,(THIS_FILE, " test_resolve() error 40: addr_len mismatch"));
+ return 40;
+ }
+ if (ref->entry[i].type != result.servers.entry[i].type) {
+ PJ_LOG(3,(THIS_FILE, " test_resolve() error 50: transport type mismatch"));
+ return 50;
+ }
+ }
+ }
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * Perform round-robin/load balance test.
+ */
+static int round_robin_test(pj_pool_t *pool)
+{
+ enum { COUNT = 400, PCT_ALLOWANCE = 5 };
+ unsigned i;
+ struct server_hit
+ {
+ char *ip_addr;
+ unsigned percent;
+ unsigned hits;
+ } server_hit[] =
+ {
+ { "1.1.1.1", 3, 0 },
+ { "2.2.2.2", 65, 0 },
+ { "3.3.3.3", 32, 0 },
+ { "4.4.4.4", 0, 0 }
+ };
+
+ PJ_LOG(3,(THIS_FILE, " Performing round-robin/load-balance test.."));
+
+ /* Do multiple resolve request to "example.com".
+ * The resolver should select the server based on the weight proportion
+ * the the servers in the SRV entry.
+ */
+ for (i=0; i<COUNT; ++i) {
+ pjsip_host_info dest;
+ struct result result;
+ unsigned j;
+
+ dest.type = PJSIP_TRANSPORT_UDP;
+ dest.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_UDP);
+ dest.addr.host = pj_str("example.com");
+ dest.addr.port = 0;
+
+ result.status = 0x12345678;
+
+ pjsip_endpt_resolve(endpt, pool, &dest, &result, &cb);
+
+ while (result.status == 0x12345678) {
+ int i = 0;
+ pj_time_val timeout = { 1, 0 };
+ pjsip_endpt_handle_events(endpt, &timeout);
+ if (i == 1)
+ pj_dns_resolver_dump(pjsip_endpt_get_resolver(endpt), PJ_TRUE);
+ }
+
+ /* Find which server was "hit" */
+ for (j=0; j<PJ_ARRAY_SIZE(server_hit); ++j) {
+ pj_str_t tmp;
+ pj_in_addr a1;
+ pj_sockaddr_in *a2;
+
+ tmp = pj_str(server_hit[j].ip_addr);
+ a1 = pj_inet_addr(&tmp);
+ a2 = (pj_sockaddr_in*) &result.servers.entry[0].addr;
+
+ if (a1.s_addr == a2->sin_addr.s_addr) {
+ server_hit[j].hits++;
+ break;
+ }
+ }
+
+ if (j == PJ_ARRAY_SIZE(server_hit)) {
+ PJ_LOG(1,(THIS_FILE, "..round_robin_test() error 10: returned address mismatch"));
+ return 10;
+ }
+ }
+
+ /* Print the actual hit rate */
+ for (i=0; i<PJ_ARRAY_SIZE(server_hit); ++i) {
+ PJ_LOG(3,(THIS_FILE, " ..Server %s: weight=%d%%, hit %d%% times",
+ server_hit[i].ip_addr, server_hit[i].percent,
+ (server_hit[i].hits * 100) / COUNT));
+ }
+
+ /* Compare the actual hit with the weight proportion */
+ for (i=0; i<PJ_ARRAY_SIZE(server_hit); ++i) {
+ int actual_pct = (server_hit[i].hits * 100) / COUNT;
+
+ if (actual_pct + PCT_ALLOWANCE < (int)server_hit[i].percent ||
+ actual_pct - PCT_ALLOWANCE > (int)server_hit[i].percent)
+ {
+ PJ_LOG(1,(THIS_FILE,
+ "..round_robin_test() error 20: "
+ "hit rate difference for server %s (%d%%) is more than "
+ "tolerable allowance (%d%%)",
+ server_hit[i].ip_addr,
+ actual_pct - server_hit[i].percent,
+ PCT_ALLOWANCE));
+ return 20;
+ }
+ }
+
+ PJ_LOG(3,(THIS_FILE,
+ " Load balance test success, hit-rate is "
+ "within %d%% allowance", PCT_ALLOWANCE));
+ return PJ_SUCCESS;
+}
+
+
+#define C(expr) status = expr; \
+ if (status != PJ_SUCCESS) app_perror(THIS_FILE, "Error", status);
+
+static void add_ref(pjsip_server_addresses *r,
+ pjsip_transport_type_e type,
+ char *addr,
+ int port)
+{
+ pj_sockaddr_in *a;
+ pj_str_t tmp;
+
+ r->entry[r->count].type = type;
+ r->entry[r->count].priority = 0;
+ r->entry[r->count].weight = 0;
+ r->entry[r->count].addr_len = sizeof(pj_sockaddr_in);
+
+ a = (pj_sockaddr_in *)&r->entry[r->count].addr;
+ a->sin_family = PJ_AF_INET;
+ tmp = pj_str(addr);
+ a->sin_addr = pj_inet_addr(&tmp);
+ a->sin_port = pj_htons((pj_uint16_t)port);
+
+ r->count++;
+}
+
+static void create_ref(pjsip_server_addresses *r,
+ pjsip_transport_type_e type,
+ char *addr,
+ int port)
+{
+ r->count = 0;
+ add_ref(r, type, addr, port);
+}
+
+
+/*
+ * Main test entry.
+ */
+int resolve_test(void)
+{
+ pj_pool_t *pool;
+ pj_dns_resolver *resv;
+ pj_str_t nameserver;
+ pj_uint16_t port = 5353;
+ pj_status_t status;
+
+ pool = pjsip_endpt_create_pool(endpt, NULL, 4000, 4000);
+
+ status = pjsip_endpt_create_resolver(endpt, &resv);
+
+ nameserver = pj_str("192.168.0.106");
+ pj_dns_resolver_set_ns(resv, 1, &nameserver, &port);
+ pjsip_endpt_set_resolver(endpt, resv);
+
+ add_dns_entries(resv);
+
+ /* These all should be resolved as IP addresses (DNS A query) */
+ {
+ pjsip_server_addresses ref;
+ create_ref(&ref, PJSIP_TRANSPORT_UDP, "1.1.1.1", 5060);
+ status = test_resolve("IP address without transport and port", pool, PJSIP_TRANSPORT_UNSPECIFIED, "1.1.1.1", 0, &ref);
+ if (status != PJ_SUCCESS)
+ return -100;
+ }
+ {
+ pjsip_server_addresses ref;
+ create_ref(&ref, PJSIP_TRANSPORT_UDP, "1.1.1.1", 5060);
+ status = test_resolve("IP address with explicit port", pool, PJSIP_TRANSPORT_UNSPECIFIED, "1.1.1.1", 5060, &ref);
+ if (status != PJ_SUCCESS)
+ return -110;
+ }
+ {
+ pjsip_server_addresses ref;
+ create_ref(&ref, PJSIP_TRANSPORT_TCP, "1.1.1.1", 5060);
+ status = test_resolve("IP address without port (TCP)", pool, PJSIP_TRANSPORT_TCP,"1.1.1.1", 0, &ref);
+ if (status != PJ_SUCCESS)
+ return -120;
+ }
+ {
+ pjsip_server_addresses ref;
+ create_ref(&ref, PJSIP_TRANSPORT_TLS, "1.1.1.1", 5061);
+ status = test_resolve("IP address without port (TLS)", pool, PJSIP_TRANSPORT_TLS, "1.1.1.1", 0, &ref);
+ if (status != PJ_SUCCESS)
+ return -130;
+ }
+
+ /* This should be resolved as DNS A record (because port is present) */
+ {
+ pjsip_server_addresses ref;
+ create_ref(&ref, PJSIP_TRANSPORT_UDP, "5.5.5.5", 5060);
+ status = test_resolve("domain name with port should resolve to A record", pool, PJSIP_TRANSPORT_UNSPECIFIED, "example.com", 5060, &ref);
+ if (status != PJ_SUCCESS)
+ return -140;
+ }
+
+ /* This will fail to be resolved as SRV, resolver should fallback to
+ * resolving to A record.
+ */
+ {
+ pjsip_server_addresses ref;
+ create_ref(&ref, PJSIP_TRANSPORT_UDP, "2.2.2.2", 5060);
+ status = test_resolve("failure with SRV fallback to A record", pool, PJSIP_TRANSPORT_UNSPECIFIED, "sip02.example.com", 0, &ref);
+ if (status != PJ_SUCCESS)
+ return -150;
+ }
+
+ /* Same as above, but explicitly for TLS. */
+ {
+ pjsip_server_addresses ref;
+ create_ref(&ref, PJSIP_TRANSPORT_TLS, "2.2.2.2", 5061);
+ status = test_resolve("failure with SRV fallback to A record (for TLS)", pool, PJSIP_TRANSPORT_TLS, "sip02.example.com", 0, &ref);
+ if (status != PJ_SUCCESS)
+ return -150;
+ }
+
+ /* Standard DNS SRV followed by A recolution */
+ {
+ pjsip_server_addresses ref;
+ create_ref(&ref, PJSIP_TRANSPORT_UDP, "6.6.6.6", 50060);
+ status = test_resolve("standard SRV resolution", pool, PJSIP_TRANSPORT_UNSPECIFIED, "domain.com", 0, &ref);
+ if (status != PJ_SUCCESS)
+ return -155;
+ }
+
+ /* Standard DNS SRV followed by A recolution (explicit transport) */
+ {
+ pjsip_server_addresses ref;
+ create_ref(&ref, PJSIP_TRANSPORT_TCP, "6.6.6.6", 50060);
+ add_ref(&ref, PJSIP_TRANSPORT_TCP, "7.7.7.7", 50060);
+ status = test_resolve("standard SRV resolution with explicit transport (TCP)", pool, PJSIP_TRANSPORT_TCP, "domain.com", 0, &ref);
+ if (status != PJ_SUCCESS)
+ return -160;
+ }
+
+
+ /* Round robin/load balance test */
+ if (round_robin_test(pool) != 0)
+ return -170;
+
+ /* Timeout test */
+ {
+ status = test_resolve("timeout test", pool, PJSIP_TRANSPORT_UNSPECIFIED, "an.invalid.address", 0, NULL);
+ if (status == PJ_SUCCESS)
+ return -150;
+ }
+
+ return 0;
+}
+
diff --git a/pjsip/src/test-pjsip/test.c b/pjsip/src/test-pjsip/test.c
index 502f049b..c7566bb2 100644
--- a/pjsip/src/test-pjsip/test.c
+++ b/pjsip/src/test-pjsip/test.c
@@ -20,6 +20,7 @@
#include "test.h"
#include <pjlib.h>
+#include <pjlib-util.h>
#include <pjsip.h>
#define THIS_FILE "test.c"
@@ -240,6 +241,11 @@ int test_main(void)
return rc;
}
+ if ((rc=pjlib_util_init()) != PJ_SUCCESS) {
+ app_perror("pj_init", rc);
+ return rc;
+ }
+
status = init_report();
if (status != PJ_SUCCESS)
return status;
@@ -311,6 +317,10 @@ int test_main(void)
DO_TEST(transport_tcp_test());
#endif
+#if INCLUDE_RESOLVE_TEST
+ DO_TEST(resolve_test());
+#endif
+
#if INCLUDE_TSX_TEST
status = pjsip_udp_transport_start(endpt, NULL, NULL, 1, &tp);
diff --git a/pjsip/src/test-pjsip/test.h b/pjsip/src/test-pjsip/test.h
index fc0901c1..bc8db5e4 100644
--- a/pjsip/src/test-pjsip/test.h
+++ b/pjsip/src/test-pjsip/test.h
@@ -38,7 +38,7 @@ extern pjsip_endpoint *endpt;
#define INCLUDE_MESSAGING_GROUP 0
#define INCLUDE_TRANSPORT_GROUP 0
-#define INCLUDE_TSX_GROUP 1
+#define INCLUDE_TSX_GROUP 0
/*
* Include tests that normally would fail under certain gcc
@@ -56,6 +56,7 @@ extern pjsip_endpoint *endpt;
#define INCLUDE_UDP_TEST INCLUDE_TRANSPORT_GROUP
#define INCLUDE_LOOP_TEST INCLUDE_TRANSPORT_GROUP
#define INCLUDE_TCP_TEST INCLUDE_TRANSPORT_GROUP
+#define INCLUDE_RESOLVE_TEST 1
#define INCLUDE_TSX_TEST INCLUDE_TSX_GROUP
@@ -69,6 +70,7 @@ int tsx_bench(void);
int transport_udp_test(void);
int transport_loop_test(void);
int transport_tcp_test(void);
+int resolve_test(void);
struct tsx_test_param
{