Major major modifications related to ticket #485 (support for TURN-07):
- Added STUN socket transport pj_stun_sock - Integration of TURN-07 to ICE - Major refactoring in ICE stream transport to make it simpler - Major modification (i.e. API change) in almost everywhere else - Much more elaborate STUN, TURN, and ICE tests in pjnath-test git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@1988 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
parent
71c8395069
commit
ff1df04070
|
@ -37,6 +37,7 @@ SOURCE stun_auth.c
|
|||
SOURCE stun_msg.c
|
||||
SOURCE stun_msg_dump.c
|
||||
SOURCE stun_session.c
|
||||
SOURCE stun_sock.c
|
||||
SOURCE stun_transaction.c
|
||||
SOURCE turn_session.c
|
||||
SOURCE turn_sock.c
|
||||
|
|
|
@ -31,15 +31,16 @@ export _LDFLAGS := $(subst /,$(HOST_PSEP),$(PJNATH_LIB)) \
|
|||
export PJNATH_SRCDIR = ../src/pjnath
|
||||
export PJNATH_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
|
||||
errno.o ice_session.o ice_strans.o nat_detect.o stun_auth.o \
|
||||
stun_msg.o stun_msg_dump.o stun_session.o stun_transaction.o \
|
||||
turn_session.o turn_sock.o
|
||||
stun_msg.o stun_msg_dump.o stun_session.o stun_sock.o \
|
||||
stun_transaction.o turn_session.o turn_sock.o
|
||||
export PJNATH_CFLAGS += $(_CFLAGS)
|
||||
|
||||
###############################################################################
|
||||
# Defines for building test application
|
||||
#
|
||||
export PJNATH_TEST_SRCDIR = ../src/pjnath-test
|
||||
export PJNATH_TEST_OBJS += ice_test.o stun.o sess_auth.o test.o
|
||||
export PJNATH_TEST_OBJS += ice_test.o stun.o sess_auth.o server.o \
|
||||
stun_sock_test.o turn_sock_test.o test.o
|
||||
export PJNATH_TEST_CFLAGS += $(_CFLAGS)
|
||||
export PJNATH_TEST_LDFLAGS += $(_LDFLAGS)
|
||||
export PJNATH_TEST_EXE:=../bin/pjnath-test-$(TARGET_NAME)$(HOST_EXE)
|
||||
|
|
|
@ -121,6 +121,10 @@ SOURCE=..\src\pjnath\stun_session.c
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\pjnath\stun_sock.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\pjnath\stun_transaction.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -177,6 +181,10 @@ SOURCE=..\include\pjnath\stun_session.h
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\include\pjnath\stun_sock.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\include\pjnath\stun_transaction.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
|
@ -297,6 +297,10 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\pjnath\stun_sock.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\pjnath\stun_transaction.c"
|
||||
>
|
||||
|
|
|
@ -88,6 +88,13 @@ LINK32=link.exe
|
|||
# Begin Source File
|
||||
|
||||
SOURCE="..\src\pjnath-test\ice_test.c"
|
||||
|
||||
!IF "$(CFG)" == "pjnath_test - Win32 Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "pjnath_test - Win32 Debug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
|
@ -95,6 +102,10 @@ SOURCE="..\src\pjnath-test\main.c"
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE="..\src\pjnath-test\server.c"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE="..\src\pjnath-test\sess_auth.c"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -103,14 +114,26 @@ SOURCE="..\src\pjnath-test\stun.c"
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE="..\src\pjnath-test\stun_sock_test.c"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE="..\src\pjnath-test\test.c"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE="..\src\pjnath-test\turn_sock_test.c"
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE="..\src\pjnath-test\server.h"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE="..\src\pjnath-test\test.h"
|
||||
# End Source File
|
||||
# End Group
|
||||
|
|
|
@ -581,6 +581,7 @@ DEP_CPP_ERRNO=\
|
|||
!ELSEIF "$(CFG)" == "pjnath_wince - Win32 (WCE ARMV4) Release"
|
||||
|
||||
DEP_CPP_ERRNO=\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\pjlib\include\pj\addr_resolv.h"\
|
||||
"..\..\..\pjlib\include\pj\array.h"\
|
||||
"..\..\..\pjlib\include\pj\assert.h"\
|
||||
|
@ -626,6 +627,7 @@ DEP_CPP_ERRNO=\
|
|||
"..\..\..\pjlib\include\pj\list_i.h"\
|
||||
"..\..\..\pjlib\include\pj\lock.h"\
|
||||
"..\..\..\pjlib\include\pj\log.h"\
|
||||
"..\..\..\pjlib\include\pj\math.h"\
|
||||
"..\..\..\pjlib\include\pj\os.h"\
|
||||
"..\..\..\pjlib\include\pj\pool.h"\
|
||||
"..\..\..\pjlib\include\pj\pool_alt.h"\
|
||||
|
@ -1256,6 +1258,7 @@ DEP_CPP_ICE_S=\
|
|||
!ELSEIF "$(CFG)" == "pjnath_wince - Win32 (WCE ARMV4) Release"
|
||||
|
||||
DEP_CPP_ICE_S=\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\pjlib\include\pj\addr_resolv.h"\
|
||||
"..\..\..\pjlib\include\pj\array.h"\
|
||||
"..\..\..\pjlib\include\pj\assert.h"\
|
||||
|
@ -1301,6 +1304,7 @@ DEP_CPP_ICE_S=\
|
|||
"..\..\..\pjlib\include\pj\list_i.h"\
|
||||
"..\..\..\pjlib\include\pj\lock.h"\
|
||||
"..\..\..\pjlib\include\pj\log.h"\
|
||||
"..\..\..\pjlib\include\pj\math.h"\
|
||||
"..\..\..\pjlib\include\pj\os.h"\
|
||||
"..\..\..\pjlib\include\pj\pool.h"\
|
||||
"..\..\..\pjlib\include\pj\pool_alt.h"\
|
||||
|
@ -1985,6 +1989,7 @@ DEP_CPP_ICE_ST=\
|
|||
"..\..\..\pjlib-util\include\pjlib-util\dns.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\types.h"\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\pjlib\include\pj\addr_resolv.h"\
|
||||
"..\..\..\pjlib\include\pj\array.h"\
|
||||
"..\..\..\pjlib\include\pj\assert.h"\
|
||||
|
@ -2031,6 +2036,7 @@ DEP_CPP_ICE_ST=\
|
|||
"..\..\..\pjlib\include\pj\list_i.h"\
|
||||
"..\..\..\pjlib\include\pj\lock.h"\
|
||||
"..\..\..\pjlib\include\pj\log.h"\
|
||||
"..\..\..\pjlib\include\pj\math.h"\
|
||||
"..\..\..\pjlib\include\pj\os.h"\
|
||||
"..\..\..\pjlib\include\pj\pool.h"\
|
||||
"..\..\..\pjlib\include\pj\pool_alt.h"\
|
||||
|
@ -2054,7 +2060,10 @@ DEP_CPP_ICE_ST=\
|
|||
"..\..\include\pjnath\stun_config.h"\
|
||||
"..\..\include\pjnath\stun_msg.h"\
|
||||
"..\..\include\pjnath\stun_session.h"\
|
||||
"..\..\include\pjnath\stun_sock.h"\
|
||||
"..\..\include\pjnath\stun_transaction.h"\
|
||||
"..\..\include\pjnath\turn_session.h"\
|
||||
"..\..\include\pjnath\turn_sock.h"\
|
||||
"..\..\include\pjnath\types.h"\
|
||||
|
||||
|
||||
|
@ -2739,6 +2748,7 @@ DEP_CPP_NAT_D=\
|
|||
!ELSEIF "$(CFG)" == "pjnath_wince - Win32 (WCE ARMV4) Release"
|
||||
|
||||
DEP_CPP_NAT_D=\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\pjlib\include\pj\addr_resolv.h"\
|
||||
"..\..\..\pjlib\include\pj\array.h"\
|
||||
"..\..\..\pjlib\include\pj\assert.h"\
|
||||
|
@ -2785,6 +2795,7 @@ DEP_CPP_NAT_D=\
|
|||
"..\..\..\pjlib\include\pj\list_i.h"\
|
||||
"..\..\..\pjlib\include\pj\lock.h"\
|
||||
"..\..\..\pjlib\include\pj\log.h"\
|
||||
"..\..\..\pjlib\include\pj\math.h"\
|
||||
"..\..\..\pjlib\include\pj\os.h"\
|
||||
"..\..\..\pjlib\include\pj\pool.h"\
|
||||
"..\..\..\pjlib\include\pj\pool_alt.h"\
|
||||
|
@ -3469,6 +3480,7 @@ DEP_CPP_STUN_=\
|
|||
"..\..\..\pjlib-util\include\pjlib-util\hmac_sha1.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\md5.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\sha1.h"\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\pjlib\include\pj\addr_resolv.h"\
|
||||
"..\..\..\pjlib\include\pj\array.h"\
|
||||
"..\..\..\pjlib\include\pj\assert.h"\
|
||||
|
@ -3514,6 +3526,7 @@ DEP_CPP_STUN_=\
|
|||
"..\..\..\pjlib\include\pj\list_i.h"\
|
||||
"..\..\..\pjlib\include\pj\lock.h"\
|
||||
"..\..\..\pjlib\include\pj\log.h"\
|
||||
"..\..\..\pjlib\include\pj\math.h"\
|
||||
"..\..\..\pjlib\include\pj\os.h"\
|
||||
"..\..\..\pjlib\include\pj\pool.h"\
|
||||
"..\..\..\pjlib\include\pj\pool_alt.h"\
|
||||
|
@ -4166,6 +4179,7 @@ DEP_CPP_STUN_M=\
|
|||
"..\..\..\pjlib-util\include\pjlib-util\hmac_sha1.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\sha1.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\types.h"\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\pjlib\include\pj\addr_resolv.h"\
|
||||
"..\..\..\pjlib\include\pj\array.h"\
|
||||
"..\..\..\pjlib\include\pj\assert.h"\
|
||||
|
@ -4211,6 +4225,7 @@ DEP_CPP_STUN_M=\
|
|||
"..\..\..\pjlib\include\pj\list_i.h"\
|
||||
"..\..\..\pjlib\include\pj\lock.h"\
|
||||
"..\..\..\pjlib\include\pj\log.h"\
|
||||
"..\..\..\pjlib\include\pj\math.h"\
|
||||
"..\..\..\pjlib\include\pj\os.h"\
|
||||
"..\..\..\pjlib\include\pj\pool.h"\
|
||||
"..\..\..\pjlib\include\pj\pool_alt.h"\
|
||||
|
@ -4847,6 +4862,7 @@ DEP_CPP_STUN_MS=\
|
|||
!ELSEIF "$(CFG)" == "pjnath_wince - Win32 (WCE ARMV4) Release"
|
||||
|
||||
DEP_CPP_STUN_MS=\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\pjlib\include\pj\addr_resolv.h"\
|
||||
"..\..\..\pjlib\include\pj\array.h"\
|
||||
"..\..\..\pjlib\include\pj\assert.h"\
|
||||
|
@ -4892,6 +4908,7 @@ DEP_CPP_STUN_MS=\
|
|||
"..\..\..\pjlib\include\pj\list_i.h"\
|
||||
"..\..\..\pjlib\include\pj\lock.h"\
|
||||
"..\..\..\pjlib\include\pj\log.h"\
|
||||
"..\..\..\pjlib\include\pj\math.h"\
|
||||
"..\..\..\pjlib\include\pj\os.h"\
|
||||
"..\..\..\pjlib\include\pj\pool.h"\
|
||||
"..\..\..\pjlib\include\pj\pool_alt.h"\
|
||||
|
@ -5514,6 +5531,7 @@ DEP_CPP_STUN_S=\
|
|||
!ELSEIF "$(CFG)" == "pjnath_wince - Win32 (WCE ARMV4) Release"
|
||||
|
||||
DEP_CPP_STUN_S=\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\pjlib\include\pj\addr_resolv.h"\
|
||||
"..\..\..\pjlib\include\pj\array.h"\
|
||||
"..\..\..\pjlib\include\pj\assert.h"\
|
||||
|
@ -5559,6 +5577,7 @@ DEP_CPP_STUN_S=\
|
|||
"..\..\..\pjlib\include\pj\list_i.h"\
|
||||
"..\..\..\pjlib\include\pj\lock.h"\
|
||||
"..\..\..\pjlib\include\pj\log.h"\
|
||||
"..\..\..\pjlib\include\pj\math.h"\
|
||||
"..\..\..\pjlib\include\pj\os.h"\
|
||||
"..\..\..\pjlib\include\pj\pool.h"\
|
||||
"..\..\..\pjlib\include\pj\pool_alt.h"\
|
||||
|
@ -5920,6 +5939,823 @@ DEP_CPP_STUN_S=\
|
|||
"..\..\include\pjnath\types.h"\
|
||||
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\pjnath\stun_sock.c
|
||||
|
||||
!IF "$(CFG)" == "pjnath_wince - Win32 (WCE emulator) Release"
|
||||
|
||||
DEP_CPP_STUN_SO=\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\config.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\dns.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\srv_resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\types.h"\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\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_armcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_codew.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcce.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_mwcc.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_symbian.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\stdarg.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\ip_helper.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\math.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\pjnath\config.h"\
|
||||
"..\..\include\pjnath\errno.h"\
|
||||
"..\..\include\pjnath\stun_auth.h"\
|
||||
"..\..\include\pjnath\stun_config.h"\
|
||||
"..\..\include\pjnath\stun_msg.h"\
|
||||
"..\..\include\pjnath\stun_session.h"\
|
||||
"..\..\include\pjnath\stun_sock.h"\
|
||||
"..\..\include\pjnath\stun_transaction.h"\
|
||||
"..\..\include\pjnath\types.h"\
|
||||
|
||||
|
||||
!ELSEIF "$(CFG)" == "pjnath_wince - Win32 (WCE emulator) Debug"
|
||||
|
||||
DEP_CPP_STUN_SO=\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\config.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\dns.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\srv_resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\types.h"\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\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_armcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_codew.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcce.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_mwcc.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_symbian.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\stdarg.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\ip_helper.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\math.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\pjnath\config.h"\
|
||||
"..\..\include\pjnath\errno.h"\
|
||||
"..\..\include\pjnath\stun_auth.h"\
|
||||
"..\..\include\pjnath\stun_config.h"\
|
||||
"..\..\include\pjnath\stun_msg.h"\
|
||||
"..\..\include\pjnath\stun_session.h"\
|
||||
"..\..\include\pjnath\stun_sock.h"\
|
||||
"..\..\include\pjnath\stun_transaction.h"\
|
||||
"..\..\include\pjnath\types.h"\
|
||||
|
||||
|
||||
!ELSEIF "$(CFG)" == "pjnath_wince - Win32 (WCE ARMV4I) Release"
|
||||
|
||||
DEP_CPP_STUN_SO=\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\config.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\dns.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\srv_resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\types.h"\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\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_armcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_codew.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcce.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_mwcc.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_symbian.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\stdarg.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\ip_helper.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\math.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\pjnath\config.h"\
|
||||
"..\..\include\pjnath\errno.h"\
|
||||
"..\..\include\pjnath\stun_auth.h"\
|
||||
"..\..\include\pjnath\stun_config.h"\
|
||||
"..\..\include\pjnath\stun_msg.h"\
|
||||
"..\..\include\pjnath\stun_session.h"\
|
||||
"..\..\include\pjnath\stun_sock.h"\
|
||||
"..\..\include\pjnath\stun_transaction.h"\
|
||||
"..\..\include\pjnath\types.h"\
|
||||
|
||||
|
||||
!ELSEIF "$(CFG)" == "pjnath_wince - Win32 (WCE ARMV4I) Debug"
|
||||
|
||||
DEP_CPP_STUN_SO=\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\config.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\dns.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\srv_resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\types.h"\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\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_armcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_codew.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcce.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_mwcc.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_symbian.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\stdarg.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\ip_helper.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\math.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\pjnath\config.h"\
|
||||
"..\..\include\pjnath\errno.h"\
|
||||
"..\..\include\pjnath\stun_auth.h"\
|
||||
"..\..\include\pjnath\stun_config.h"\
|
||||
"..\..\include\pjnath\stun_msg.h"\
|
||||
"..\..\include\pjnath\stun_session.h"\
|
||||
"..\..\include\pjnath\stun_sock.h"\
|
||||
"..\..\include\pjnath\stun_transaction.h"\
|
||||
"..\..\include\pjnath\types.h"\
|
||||
|
||||
|
||||
!ELSEIF "$(CFG)" == "pjnath_wince - Win32 (WCE ARMV4) Release"
|
||||
|
||||
DEP_CPP_STUN_SO=\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\config.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\dns.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\srv_resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\types.h"\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\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_armcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_codew.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcce.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_mwcc.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_symbian.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\stdarg.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\ip_helper.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\math.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\pjnath\config.h"\
|
||||
"..\..\include\pjnath\errno.h"\
|
||||
"..\..\include\pjnath\stun_auth.h"\
|
||||
"..\..\include\pjnath\stun_config.h"\
|
||||
"..\..\include\pjnath\stun_msg.h"\
|
||||
"..\..\include\pjnath\stun_session.h"\
|
||||
"..\..\include\pjnath\stun_sock.h"\
|
||||
"..\..\include\pjnath\stun_transaction.h"\
|
||||
"..\..\include\pjnath\types.h"\
|
||||
|
||||
|
||||
!ELSEIF "$(CFG)" == "pjnath_wince - Win32 (WCE ARMV4) Debug"
|
||||
|
||||
DEP_CPP_STUN_SO=\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\config.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\dns.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\srv_resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\types.h"\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\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_armcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_codew.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcce.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_mwcc.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_symbian.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\stdarg.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\ip_helper.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\math.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\pjnath\config.h"\
|
||||
"..\..\include\pjnath\errno.h"\
|
||||
"..\..\include\pjnath\stun_auth.h"\
|
||||
"..\..\include\pjnath\stun_config.h"\
|
||||
"..\..\include\pjnath\stun_msg.h"\
|
||||
"..\..\include\pjnath\stun_session.h"\
|
||||
"..\..\include\pjnath\stun_sock.h"\
|
||||
"..\..\include\pjnath\stun_transaction.h"\
|
||||
"..\..\include\pjnath\types.h"\
|
||||
|
||||
|
||||
!ELSEIF "$(CFG)" == "pjnath_wince - Win32 (WCE ARMV4T) Release"
|
||||
|
||||
DEP_CPP_STUN_SO=\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\config.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\dns.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\srv_resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\types.h"\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\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_armcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_codew.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcce.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_mwcc.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_symbian.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\stdarg.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\ip_helper.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\math.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\pjnath\config.h"\
|
||||
"..\..\include\pjnath\errno.h"\
|
||||
"..\..\include\pjnath\stun_auth.h"\
|
||||
"..\..\include\pjnath\stun_config.h"\
|
||||
"..\..\include\pjnath\stun_msg.h"\
|
||||
"..\..\include\pjnath\stun_session.h"\
|
||||
"..\..\include\pjnath\stun_sock.h"\
|
||||
"..\..\include\pjnath\stun_transaction.h"\
|
||||
"..\..\include\pjnath\types.h"\
|
||||
|
||||
|
||||
!ELSEIF "$(CFG)" == "pjnath_wince - Win32 (WCE ARMV4T) Debug"
|
||||
|
||||
DEP_CPP_STUN_SO=\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\config.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\dns.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\srv_resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\types.h"\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\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_armcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_codew.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcce.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_mwcc.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_symbian.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\stdarg.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\ip_helper.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\math.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\pjnath\config.h"\
|
||||
"..\..\include\pjnath\errno.h"\
|
||||
"..\..\include\pjnath\stun_auth.h"\
|
||||
"..\..\include\pjnath\stun_config.h"\
|
||||
"..\..\include\pjnath\stun_msg.h"\
|
||||
"..\..\include\pjnath\stun_session.h"\
|
||||
"..\..\include\pjnath\stun_sock.h"\
|
||||
"..\..\include\pjnath\stun_transaction.h"\
|
||||
"..\..\include\pjnath\types.h"\
|
||||
|
||||
|
||||
!ELSEIF "$(CFG)" == "pjnath_wince - Win32 (WCE x86) Release"
|
||||
|
||||
DEP_CPP_STUN_SO=\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\config.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\dns.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\srv_resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\types.h"\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\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_armcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_codew.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcce.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_mwcc.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_symbian.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\stdarg.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\ip_helper.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\math.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\pjnath\config.h"\
|
||||
"..\..\include\pjnath\errno.h"\
|
||||
"..\..\include\pjnath\stun_auth.h"\
|
||||
"..\..\include\pjnath\stun_config.h"\
|
||||
"..\..\include\pjnath\stun_msg.h"\
|
||||
"..\..\include\pjnath\stun_session.h"\
|
||||
"..\..\include\pjnath\stun_sock.h"\
|
||||
"..\..\include\pjnath\stun_transaction.h"\
|
||||
"..\..\include\pjnath\types.h"\
|
||||
|
||||
|
||||
!ELSEIF "$(CFG)" == "pjnath_wince - Win32 (WCE x86) Debug"
|
||||
|
||||
DEP_CPP_STUN_SO=\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\config.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\dns.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\srv_resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\types.h"\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\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_armcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_codew.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_gcce.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
|
||||
"..\..\..\pjlib\include\pj\compat\cc_mwcc.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_symbian.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\stdarg.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\ip_helper.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\math.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\pjnath\config.h"\
|
||||
"..\..\include\pjnath\errno.h"\
|
||||
"..\..\include\pjnath\stun_auth.h"\
|
||||
"..\..\include\pjnath\stun_config.h"\
|
||||
"..\..\include\pjnath\stun_msg.h"\
|
||||
"..\..\include\pjnath\stun_session.h"\
|
||||
"..\..\include\pjnath\stun_sock.h"\
|
||||
"..\..\include\pjnath\stun_transaction.h"\
|
||||
"..\..\include\pjnath\types.h"\
|
||||
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
|
@ -6196,6 +7032,7 @@ DEP_CPP_STUN_T=\
|
|||
!ELSEIF "$(CFG)" == "pjnath_wince - Win32 (WCE ARMV4) Release"
|
||||
|
||||
DEP_CPP_STUN_T=\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\pjlib\include\pj\addr_resolv.h"\
|
||||
"..\..\..\pjlib\include\pj\array.h"\
|
||||
"..\..\..\pjlib\include\pj\assert.h"\
|
||||
|
@ -6241,6 +7078,7 @@ DEP_CPP_STUN_T=\
|
|||
"..\..\..\pjlib\include\pj\list_i.h"\
|
||||
"..\..\..\pjlib\include\pj\lock.h"\
|
||||
"..\..\..\pjlib\include\pj\log.h"\
|
||||
"..\..\..\pjlib\include\pj\math.h"\
|
||||
"..\..\..\pjlib\include\pj\os.h"\
|
||||
"..\..\..\pjlib\include\pj\pool.h"\
|
||||
"..\..\..\pjlib\include\pj\pool_alt.h"\
|
||||
|
@ -6926,6 +7764,7 @@ DEP_CPP_TURN_=\
|
|||
"..\..\..\pjlib-util\include\pjlib-util\resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\srv_resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\types.h"\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\pjlib\include\pj\addr_resolv.h"\
|
||||
"..\..\..\pjlib\include\pj\array.h"\
|
||||
"..\..\..\pjlib\include\pj\assert.h"\
|
||||
|
@ -6971,6 +7810,7 @@ DEP_CPP_TURN_=\
|
|||
"..\..\..\pjlib\include\pj\list_i.h"\
|
||||
"..\..\..\pjlib\include\pj\lock.h"\
|
||||
"..\..\..\pjlib\include\pj\log.h"\
|
||||
"..\..\..\pjlib\include\pj\math.h"\
|
||||
"..\..\..\pjlib\include\pj\os.h"\
|
||||
"..\..\..\pjlib\include\pj\pool.h"\
|
||||
"..\..\..\pjlib\include\pj\pool_alt.h"\
|
||||
|
@ -7718,6 +8558,7 @@ DEP_CPP_TURN_S=\
|
|||
"..\..\..\pjlib-util\include\pjlib-util\dns.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\resolver.h"\
|
||||
"..\..\..\pjlib-util\include\pjlib-util\types.h"\
|
||||
"..\..\..\pjlib\include\pj\activesock.h"\
|
||||
"..\..\..\pjlib\include\pj\addr_resolv.h"\
|
||||
"..\..\..\pjlib\include\pj\array.h"\
|
||||
"..\..\..\pjlib\include\pj\assert.h"\
|
||||
|
@ -7763,6 +8604,7 @@ DEP_CPP_TURN_S=\
|
|||
"..\..\..\pjlib\include\pj\list_i.h"\
|
||||
"..\..\..\pjlib\include\pj\lock.h"\
|
||||
"..\..\..\pjlib\include\pj\log.h"\
|
||||
"..\..\..\pjlib\include\pj\math.h"\
|
||||
"..\..\..\pjlib\include\pj\os.h"\
|
||||
"..\..\..\pjlib\include\pj\pool.h"\
|
||||
"..\..\..\pjlib\include\pj\pool_alt.h"\
|
||||
|
|
Binary file not shown.
Binary file not shown.
Before (image error) Size: 32 KiB After (image error) Size: 124 KiB |
|
@ -26,6 +26,7 @@
|
|||
#include <pjnath/stun_config.h>
|
||||
#include <pjnath/stun_msg.h>
|
||||
#include <pjnath/stun_session.h>
|
||||
#include <pjnath/stun_sock.h>
|
||||
#include <pjnath/stun_transaction.h>
|
||||
#include <pjnath/turn_session.h>
|
||||
#include <pjnath/turn_sock.h>
|
||||
|
|
|
@ -141,6 +141,84 @@
|
|||
#endif
|
||||
|
||||
|
||||
/* **************************************************************************
|
||||
* STUN TRANSPORT CONFIGURATION
|
||||
*/
|
||||
|
||||
/**
|
||||
* The packet buffer size for the STUN transport.
|
||||
*/
|
||||
#ifndef PJ_STUN_SOCK_PKT_LEN
|
||||
# define PJ_STUN_SOCK_PKT_LEN 2000
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* The duration of the STUN keep-alive period, in seconds.
|
||||
*/
|
||||
#ifndef PJ_STUN_KEEP_ALIVE_SEC
|
||||
# define PJ_STUN_KEEP_ALIVE_SEC 15
|
||||
#endif
|
||||
|
||||
|
||||
/* **************************************************************************
|
||||
* TURN CONFIGURATION
|
||||
*/
|
||||
|
||||
/**
|
||||
* Maximum DNS SRV entries to be processed in the DNS SRV response
|
||||
*/
|
||||
#ifndef PJ_TURN_MAX_DNS_SRV_CNT
|
||||
# define PJ_TURN_MAX_DNS_SRV_CNT 4
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Maximum TURN packet size to be supported.
|
||||
*/
|
||||
#ifndef PJ_TURN_MAX_PKT_LEN
|
||||
# define PJ_TURN_MAX_PKT_LEN 3000
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* The TURN permission lifetime setting. This value should be taken from the
|
||||
* TURN protocol specification.
|
||||
*/
|
||||
#ifndef PJ_TURN_PERM_TIMEOUT
|
||||
# define PJ_TURN_PERM_TIMEOUT 300
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* The TURN channel binding lifetime. This value should be taken from the
|
||||
* TURN protocol specification.
|
||||
*/
|
||||
#ifndef PJ_TURN_CHANNEL_TIMEOUT
|
||||
# define PJ_TURN_CHANNEL_TIMEOUT 600
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Number of seconds to refresh the permission/channel binding before the
|
||||
* permission/channel binding expires. This value should be greater than
|
||||
* PJ_TURN_PERM_TIMEOUT setting.
|
||||
*/
|
||||
#ifndef PJ_TURN_REFRESH_SEC_BEFORE
|
||||
# define PJ_TURN_REFRESH_SEC_BEFORE 60
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* The TURN session timer heart beat interval. When this timer occurs, the
|
||||
* TURN session will scan all the permissions/channel bindings to see which
|
||||
* need to be refreshed.
|
||||
*/
|
||||
#ifndef PJ_TURN_KEEP_ALIVE_SEC
|
||||
# define PJ_TURN_KEEP_ALIVE_SEC 15
|
||||
#endif
|
||||
|
||||
|
||||
/* **************************************************************************
|
||||
* ICE CONFIGURATION
|
||||
*/
|
||||
|
|
|
@ -121,6 +121,15 @@
|
|||
#define PJNATH_ESTUNINSERVER (PJNATH_ERRNO_START+42) /* 370042 */
|
||||
|
||||
|
||||
/************************************************************
|
||||
* STUN SESSION/TRANSPORT ERROR CODES
|
||||
***********************************************************/
|
||||
/**
|
||||
* @hideinitializer
|
||||
* STUN object has been destoyed.
|
||||
*/
|
||||
#define PJNATH_ESTUNDESTROYED (PJNATH_ERRNO_START+60) /* 370060 */
|
||||
|
||||
|
||||
/************************************************************
|
||||
* ICE ERROR CODES
|
||||
|
|
|
@ -128,6 +128,11 @@ PJ_BEGIN_DECL
|
|||
* application via \a on_rx_data callback.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Forward declaration for checklist.
|
||||
*/
|
||||
typedef struct pj_ice_sess_checklist pj_ice_sess_checklist;
|
||||
|
||||
/**
|
||||
* This enumeration describes the type of an ICE candidate.
|
||||
*/
|
||||
|
@ -193,6 +198,24 @@ typedef struct pj_ice_sess_comp
|
|||
} pj_ice_sess_comp;
|
||||
|
||||
|
||||
/**
|
||||
* Data structure to be attached to internal message processing.
|
||||
*/
|
||||
typedef struct pj_ice_msg_data
|
||||
{
|
||||
unsigned transport_id;
|
||||
pj_bool_t has_req_data;
|
||||
|
||||
union data {
|
||||
struct request_data {
|
||||
pj_ice_sess *ice;
|
||||
pj_ice_sess_checklist *clist;
|
||||
unsigned ckid;
|
||||
} req;
|
||||
} data;
|
||||
} pj_ice_msg_data;
|
||||
|
||||
|
||||
/**
|
||||
* This structure describes an ICE candidate.
|
||||
* ICE candidate is a transport address that is to be tested by ICE
|
||||
|
@ -203,17 +226,35 @@ typedef struct pj_ice_sess_comp
|
|||
*/
|
||||
typedef struct pj_ice_sess_cand
|
||||
{
|
||||
/**
|
||||
* The candidate type, as described in #pj_ice_cand_type enumeration.
|
||||
*/
|
||||
pj_ice_cand_type type;
|
||||
|
||||
/**
|
||||
* Status of this candidate. The value will be PJ_SUCCESS if candidate
|
||||
* address has been resolved successfully, PJ_EPENDING when the address
|
||||
* resolution process is in progress, or other value when the address
|
||||
* resolution has completed with failure.
|
||||
*/
|
||||
pj_status_t status;
|
||||
|
||||
/**
|
||||
* The component ID of this candidate. Note that component IDs starts
|
||||
* with one for RTP and two for RTCP. In other words, it's not zero
|
||||
* based.
|
||||
*/
|
||||
pj_uint32_t comp_id;
|
||||
pj_uint8_t comp_id;
|
||||
|
||||
/**
|
||||
* The candidate type, as described in #pj_ice_cand_type enumeration.
|
||||
* Transport ID to be used to send packets for this candidate.
|
||||
*/
|
||||
pj_ice_cand_type type;
|
||||
pj_uint8_t transport_id;
|
||||
|
||||
/**
|
||||
* Local preference value, which typically is 65535.
|
||||
*/
|
||||
pj_uint16_t local_pref;
|
||||
|
||||
/**
|
||||
* The foundation string, which is an identifier which value will be
|
||||
|
@ -383,7 +424,7 @@ typedef enum pj_ice_sess_checklist_state
|
|||
* This structure represents ICE check list, that is an ordered set of
|
||||
* candidate pairs that an agent will use to generate checks.
|
||||
*/
|
||||
typedef struct pj_ice_sess_checklist
|
||||
struct pj_ice_sess_checklist
|
||||
{
|
||||
/**
|
||||
* The checklist state.
|
||||
|
@ -405,7 +446,7 @@ typedef struct pj_ice_sess_checklist
|
|||
*/
|
||||
pj_timer_entry timer;
|
||||
|
||||
} pj_ice_sess_checklist;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
|
@ -430,12 +471,14 @@ typedef struct pj_ice_sess_cb
|
|||
*
|
||||
* @param ice The ICE session.
|
||||
* @param comp_id ICE component ID.
|
||||
* @param transport_id Transport ID.
|
||||
* @param pkt The STUN packet.
|
||||
* @param size The size of the packet.
|
||||
* @param dst_addr Packet destination address.
|
||||
* @param dst_addr_len Length of destination address.
|
||||
*/
|
||||
pj_status_t (*on_tx_pkt)(pj_ice_sess *ice, unsigned comp_id,
|
||||
unsigned transport_id,
|
||||
const void *pkt, pj_size_t size,
|
||||
const pj_sockaddr_t *dst_addr,
|
||||
unsigned dst_addr_len);
|
||||
|
@ -446,6 +489,7 @@ typedef struct pj_ice_sess_cb
|
|||
*
|
||||
* @param ice The ICE session.
|
||||
* @param comp_id ICE component ID.
|
||||
* @param transport_id Transport ID.
|
||||
* @param pkt The whole packet.
|
||||
* @param size Size of the packet.
|
||||
* @param src_addr Source address where this packet was received
|
||||
|
@ -453,6 +497,7 @@ typedef struct pj_ice_sess_cb
|
|||
* @param src_addr_len The length of source address.
|
||||
*/
|
||||
void (*on_rx_data)(pj_ice_sess *ice, unsigned comp_id,
|
||||
unsigned transport_id,
|
||||
void *pkt, pj_size_t size,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len);
|
||||
|
@ -496,6 +541,7 @@ typedef struct pj_ice_rx_check
|
|||
PJ_DECL_LIST_MEMBER(struct pj_ice_rx_check);
|
||||
|
||||
unsigned comp_id; /**< Component ID. */
|
||||
unsigned transport_id; /**< Transport ID. */
|
||||
|
||||
pj_sockaddr src_addr; /**< Source address of request */
|
||||
unsigned src_addr_len; /**< Length of src address. */
|
||||
|
@ -553,6 +599,9 @@ struct pj_ice_sess
|
|||
unsigned rcand_cnt; /**< # of remote cand. */
|
||||
pj_ice_sess_cand rcand[PJ_ICE_MAX_CAND]; /**< Array of cand. */
|
||||
|
||||
/* Array of transport datas */
|
||||
pj_ice_msg_data tp_data[4];
|
||||
|
||||
/* List of eearly checks */
|
||||
pj_ice_rx_check early_check; /**< Early checks. */
|
||||
|
||||
|
@ -581,6 +630,17 @@ struct pj_ice_sess
|
|||
PJ_DECL(const char*) pj_ice_get_cand_type_name(pj_ice_cand_type type);
|
||||
|
||||
|
||||
/**
|
||||
* This is a utility function to retrieve the string name for the
|
||||
* particular role type.
|
||||
*
|
||||
* @param role Role type.
|
||||
*
|
||||
* @return The string representation of the role.
|
||||
*/
|
||||
PJ_DECL(const char*) pj_ice_sess_role_name(pj_ice_sess_role role);
|
||||
|
||||
|
||||
/**
|
||||
* This is a utility function to calculate the foundation identification
|
||||
* for a candidate.
|
||||
|
@ -685,6 +745,8 @@ PJ_DECL(pj_status_t) pj_ice_sess_set_prefs(pj_ice_sess *ice,
|
|||
*
|
||||
* @param ice ICE session instance.
|
||||
* @param comp_id Component ID of this candidate.
|
||||
* @param transport_id Transport ID to be used to send packets for this
|
||||
* candidate.
|
||||
* @param type Candidate type.
|
||||
* @param local_pref Local preference for this candidate, which
|
||||
* normally should be set to 65535.
|
||||
|
@ -699,6 +761,7 @@ PJ_DECL(pj_status_t) pj_ice_sess_set_prefs(pj_ice_sess *ice,
|
|||
*/
|
||||
PJ_DECL(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
|
||||
unsigned comp_id,
|
||||
unsigned transport_id,
|
||||
pj_ice_cand_type type,
|
||||
pj_uint16_t local_pref,
|
||||
const pj_str_t *foundation,
|
||||
|
@ -797,6 +860,9 @@ PJ_DECL(pj_status_t) pj_ice_sess_send_data(pj_ice_sess *ice,
|
|||
*
|
||||
* @param ice The ICE session.
|
||||
* @param comp_id Component ID.
|
||||
* @param transport_id Number to identify where this packet was received
|
||||
* from. This parameter will be returned back to
|
||||
* application in \a on_tx_pkt() callback.
|
||||
* @param pkt Incoming packet.
|
||||
* @param pkt_size Size of incoming packet.
|
||||
* @param src_addr Source address of the packet.
|
||||
|
@ -806,6 +872,7 @@ PJ_DECL(pj_status_t) pj_ice_sess_send_data(pj_ice_sess *ice,
|
|||
*/
|
||||
PJ_DECL(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice,
|
||||
unsigned comp_id,
|
||||
unsigned transport_id,
|
||||
void *pkt,
|
||||
pj_size_t pkt_size,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
* @brief ICE Stream Transport
|
||||
*/
|
||||
#include <pjnath/ice_session.h>
|
||||
#include <pjnath/stun_sock.h>
|
||||
#include <pjnath/turn_sock.h>
|
||||
#include <pjlib-util/resolver.h>
|
||||
#include <pj/ioqueue.h>
|
||||
#include <pj/timer.h>
|
||||
|
@ -44,137 +46,28 @@ PJ_BEGIN_DECL
|
|||
* library.
|
||||
*
|
||||
* ICE stream transport, as represented by #pj_ice_strans structure, is an ICE
|
||||
* capable component for transporting media streams within a media session.
|
||||
* capable class for transporting media streams within a media session.
|
||||
* It consists of one or more transport sockets (typically two for RTP
|
||||
* based communication - one for RTP and one for RTCP), and an
|
||||
* \ref PJNATH_ICE_SESSION for performing connectivity checks among the.
|
||||
* various candidates of the transport addresses.
|
||||
*
|
||||
* \section PJNATH_ICE_STREAM_TRANSPORT_USING Using the ICE Stream Transport
|
||||
*
|
||||
* Application may use the ICE stream transport in two ways:
|
||||
* - it can create the ICE stream transports once during application
|
||||
* initialization and keep them alive throughout application lifetime, or
|
||||
* - it can create and destroy the ICE stream transport as needed everytime
|
||||
* a call is made and destroyed.
|
||||
*
|
||||
* Keeping the ICE stream transport alive throughout
|
||||
* application's lifetime is normally preferable, as initializing the
|
||||
* ICE stream transport may incur delay because the ICE stream transport
|
||||
* would need to communicate with the STUN/TURN server to get the
|
||||
* server reflexive and relayed candidates for the transports.
|
||||
*
|
||||
* Regardless of which usage scenario is being used, the ICE stream
|
||||
* transport is capable for restarting the ICE session being used and to
|
||||
* send STUN keep-alives for its STUN server reflexive and relayed
|
||||
* candidates. When ICE stream transport detects that the STUN mapped
|
||||
* address has changed in the keep-alive response, it will automatically
|
||||
* update its address to the new address, and notify the application via
|
||||
* \a on_addr_change() function of the #pj_ice_strans_cb callback.
|
||||
*
|
||||
* \subsection PJNATH_ICE_ST_TRA_INIT Initialization
|
||||
*
|
||||
* Application creates the ICE stream transport by calling
|
||||
* #pj_ice_strans_create() function. Among other things, application needs
|
||||
* to specify:
|
||||
* - STUN configuration (pj_stun_config), containing STUN settings
|
||||
* such as timeout values and the instances of timer heap and
|
||||
* ioqueue.
|
||||
* - Session name, useful for identifying this session in the log.
|
||||
* - Number of ICE components.
|
||||
* - Arbitrary user data, useful when associating the ICE session
|
||||
* with some application's data structure.
|
||||
* - A callback (#pj_ice_strans_cb) to receive events from the ICE
|
||||
* stream transport. Two of the most important fields in this
|
||||
* callback structure are \a on_rx_data() to notify application
|
||||
* about incoming data (perhaps RTP or RTCP packet), and
|
||||
* \a on_ice_complete() to notify application that ICE negotiation
|
||||
* has completed, either successfully or with failure.
|
||||
*
|
||||
* After the ICE stream transport is created, application may set up the
|
||||
* STUN servers to be used to obtain STUN server reflexive and relayed
|
||||
* candidate, by calling #pj_ice_strans_set_stun_domain() or
|
||||
* #pj_ice_strans_set_stun_srv().
|
||||
*
|
||||
* Application then creates each component by calling
|
||||
* #pj_ice_strans_create_comp(); this would create an actual socket
|
||||
* which listens to the specified local address, and it would also
|
||||
* perform lookup to find various transport address candidates for this
|
||||
* socket.
|
||||
*
|
||||
* Adding component may involve contacting STUN and TURN servers to get
|
||||
* STUN mapped address and allocate TURN relay channel, and this process
|
||||
* may take some time to complete. Once application has added all
|
||||
* components, it can check whether server reflexive and relayed
|
||||
* candidates have been acquired, by calling #pj_ice_strans_get_comps_status().
|
||||
*
|
||||
* \subsection PJNATH_ICE_ST_TRA_INIT_ICE Starting ICE Session
|
||||
*
|
||||
* When application is about to send an offer containing ICE capability,
|
||||
* or when it receives an offer containing ICE capability, it would
|
||||
* create the ICE session by calling #pj_ice_strans_init_ice(). This would
|
||||
* register all transport address aliases for each component to the ICE
|
||||
* session as candidates. After this application can enumerate all local
|
||||
* candidates by calling #pj_ice_strans_enum_cands(), and encode these
|
||||
* candidates in the SDP to be sent to remote agent.
|
||||
*
|
||||
* \subsection PJNATH_ICE_ST_TRA_START Starting Connectivity Checks
|
||||
*
|
||||
* Once application receives the SDP from remote, it pairs local candidates
|
||||
* with remote candidates, and can start ICE connectivity checks. This is
|
||||
* done by calling #pj_ice_strans_start_ice(), specifying
|
||||
* the remote candidate list, and remote username and password. If the
|
||||
* pairing process is successful, ICE connectivity checks will begin
|
||||
* immediately. The ICE session/transport will then notify the application
|
||||
* via the callback when ICE connectivity checks completes, either
|
||||
* successfully or with failure.
|
||||
*
|
||||
* \subsection PJNATH_ICE_ST_TRA_SEND_RECV Sending and Receiving Data
|
||||
*
|
||||
* Application can send data (normally RTP or RTCP packets) at any time
|
||||
* by calling #pj_ice_strans_sendto(). This function takes a destination
|
||||
* address as one of the arguments, and this destination address should
|
||||
* be taken from the default transport address of the component (that is
|
||||
* the address in SDP c= and m= lines, or in a=rtcp attribute).
|
||||
* If ICE negotiation is in progress, this function will send the data
|
||||
* to the destination address. Otherwise if ICE negotiation has completed
|
||||
* successfully, this function will send the data to the nominated remote
|
||||
* address, as negotiated by ICE.
|
||||
*
|
||||
* Upon receiving incoming data (that is a non-STUN message), the ICE
|
||||
* stream transport will notify the application by calling \a on_rx_data()
|
||||
* of the #pj_ice_strans_cb callback.
|
||||
*
|
||||
* \subsection PJNATH_ICE_ST_TRA_STOP Stopping ICE Session
|
||||
*
|
||||
* Once the call is terminated, application no longer needs to keep the
|
||||
* ICE session, so it should call #pj_ice_strans_stop_ice() to destroy the
|
||||
* ICE session within this ICE stream transport. Note that this WILL NOT
|
||||
* destroy the sockets/transports, it only destroys the ICE session
|
||||
* within this ICE stream transport. It is recommended that application
|
||||
* retains the ICE stream transport to speed up the process of setting up
|
||||
* the next call. The ICE stream transport will continue to send STUN
|
||||
* keep-alive packets to keep the NAT binding open and to detect change
|
||||
* in STUN mapped address.
|
||||
*
|
||||
* \subsection PJNATH_ICE_ST_TRA_RESTART Restarting ICE Session
|
||||
*
|
||||
* When a new call is made, application can repeat the above
|
||||
* #pj_ice_strans_init_ice() to #pj_ice_strans_stop_ice() cycle for
|
||||
* the new call, using this same ICE stream transport.
|
||||
*
|
||||
* \subsection PJNATH_ICE_ST_TRA_DESTROY Destroying ICE Stream Transport
|
||||
*
|
||||
* Finally, when the ICE stream transport itself is no longer needed,
|
||||
* for example when the application quits, application should call
|
||||
* #pj_ice_strans_destroy() to release back all resources allocated by this
|
||||
* ICE stream transport.
|
||||
*
|
||||
*/
|
||||
|
||||
/** Forward declaration for ICE stream transport. */
|
||||
typedef struct pj_ice_strans pj_ice_strans;
|
||||
|
||||
/** Transport operation types to be reported on \a on_status() callback */
|
||||
typedef enum pj_ice_strans_op
|
||||
{
|
||||
/** Initialization (candidate gathering) */
|
||||
PJ_ICE_STRANS_OP_INIT,
|
||||
|
||||
/** Negotiation */
|
||||
PJ_ICE_STRANS_OP_NEGOTIATION
|
||||
|
||||
} pj_ice_strans_op;
|
||||
|
||||
/**
|
||||
* This structure contains callbacks that will be called by the
|
||||
* ICE stream transport.
|
||||
|
@ -200,195 +93,200 @@ typedef struct pj_ice_strans_cb
|
|||
unsigned src_addr_len);
|
||||
|
||||
/**
|
||||
* This callback will be called when ICE checks have completed.
|
||||
* This callback is optional.
|
||||
* Callback to report status.
|
||||
*
|
||||
* @param ice_st The ICE stream transport.
|
||||
* @param status The ICE connectivity check status.
|
||||
* @param op The operation
|
||||
* @param status Operation status.
|
||||
*/
|
||||
void (*on_ice_complete)(pj_ice_strans *ice_st,
|
||||
pj_ice_strans_op op,
|
||||
pj_status_t status);
|
||||
|
||||
/**
|
||||
* This callback will be called when ICE transport has detected that
|
||||
* the STUN mapped address of a candidate has changed.
|
||||
*
|
||||
* @param ice_st The ICE stream transport.
|
||||
* @param comp_id Component ID.
|
||||
* @param cand_id Candidate ID.
|
||||
*/
|
||||
void (*on_addr_change)(pj_ice_strans *ice_st,
|
||||
unsigned comp_id,
|
||||
unsigned cand_id);
|
||||
|
||||
} pj_ice_strans_cb;
|
||||
|
||||
|
||||
/**
|
||||
* Various flags that can be specified when creating a component with
|
||||
* #pj_ice_strans_create_comp(). These options may be combined together
|
||||
* with bitmask operation.
|
||||
* This structure describes ICE stream transport configuration. Application
|
||||
* should initialize the structure by calling #pj_ice_strans_cfg_default()
|
||||
* before changing the settings.
|
||||
*/
|
||||
enum pj_ice_strans_option
|
||||
typedef struct pj_ice_strans_cfg
|
||||
{
|
||||
/**
|
||||
* If this option is specified, only a listening socket will be
|
||||
* created for the component, and no candidate will be added to
|
||||
* the component. Application must add the component manually
|
||||
* by inspecting the socket and transport address of the component.
|
||||
* Address family, IPv4 or IPv6. Currently only pj_AF_INET() (IPv4)
|
||||
* is supported, and this is the default value.
|
||||
*/
|
||||
PJ_ICE_ST_OPT_DONT_ADD_CAND = 1,
|
||||
int af;
|
||||
|
||||
/**
|
||||
* If this option is specified, then no STUN reflexive candidate
|
||||
* will be added to the component.
|
||||
*/
|
||||
PJ_ICE_ST_OPT_DISABLE_STUN = 2,
|
||||
|
||||
/**
|
||||
* If this option is specified, then no STUN relay candidate
|
||||
* will be added to the component.
|
||||
*/
|
||||
PJ_ICE_ST_OPT_DISABLE_RELAY = 4,
|
||||
|
||||
/**
|
||||
* If this option is specified, then when the function fails to
|
||||
* bind the socket to the specified port, it WILL NOT try to
|
||||
* bind the socket to the next available port.
|
||||
* STUN configuration which contains the timer heap and
|
||||
* ioqueue instance to be used, and STUN retransmission
|
||||
* settings. This setting is mandatory.
|
||||
*
|
||||
* If this option is NOT specified, then the function will try to
|
||||
* bind the socket to next port+2, repetitively until the socket
|
||||
* is bound successfully.
|
||||
* The default value is all zero. Application must initialize
|
||||
* this setting with #pj_stun_config_init().
|
||||
*/
|
||||
PJ_ICE_ST_OPT_NO_PORT_RETRY = 8,
|
||||
};
|
||||
pj_stun_config stun_cfg;
|
||||
|
||||
|
||||
/**
|
||||
* This structure describes ICE stream transport candidate. A "candidate"
|
||||
* in ICE stream transport can be viewed as alias transport address
|
||||
* for the socket.
|
||||
*/
|
||||
typedef struct pj_ice_strans_cand
|
||||
{
|
||||
/**
|
||||
* Candidate type.
|
||||
*/
|
||||
pj_ice_cand_type type;
|
||||
|
||||
/**
|
||||
* Status of this candidate. This status is useful for ICE reflexive
|
||||
* and relay candidate, where the address needs to be resolved
|
||||
* asynchronously by sending STUN request to STUN server.
|
||||
* DNS resolver to be used to resolve servers. If DNS SRV
|
||||
* resolution is required, the resolver must be set.
|
||||
*
|
||||
* The value will be PJ_SUCCESS if candidate address has been resolved
|
||||
* successfully, PJ_EPENDING when the address resolution process is
|
||||
* in progress, or other value when the address resolution has
|
||||
* completed with failure.
|
||||
* The default value is NULL.
|
||||
*/
|
||||
pj_status_t status;
|
||||
pj_dns_resolver *resolver;
|
||||
|
||||
/**
|
||||
* The candidate transport address.
|
||||
* STUN and local transport settings. This specifies the
|
||||
* settings for local UDP socket, which will be resolved
|
||||
* to get the STUN mapped address.
|
||||
*/
|
||||
pj_sockaddr addr;
|
||||
struct {
|
||||
/**
|
||||
* Optional configuration for STUN transport. The default
|
||||
* value will be initialized with #pj_stun_sock_cfg_default().
|
||||
*/
|
||||
pj_stun_sock_cfg cfg;
|
||||
|
||||
/**
|
||||
* Disable host candidates. When this option is set, no
|
||||
* host candidates will be added.
|
||||
*
|
||||
* Default: PJ_FALSE
|
||||
*/
|
||||
pj_bool_t no_host_cands;
|
||||
|
||||
/**
|
||||
* Include loopback addresses in the host candidates.
|
||||
*
|
||||
* Default: PJ_FALSE
|
||||
*/
|
||||
pj_bool_t loop_addr;
|
||||
|
||||
/**
|
||||
* Specify the STUN server domain or hostname or IP address.
|
||||
* If DNS SRV resolution is required, application must fill
|
||||
* in this setting with the domain name of the STUN server
|
||||
* and set the resolver instance in the \a resolver field.
|
||||
* Otherwise if the \a resolver setting is not set, this
|
||||
* field will be resolved with hostname resolution and in
|
||||
* this case the \a port field must be set.
|
||||
*
|
||||
* The \a port field should also be set even when DNS SRV
|
||||
* resolution is used, in case the DNS SRV resolution fails.
|
||||
*
|
||||
* When this field is empty, STUN mapped address resolution
|
||||
* will not be performed. In this case only ICE host candidates
|
||||
* will be added to the ICE transport, unless if \a no_host_cands
|
||||
* field is set. In this case, both host and srflx candidates
|
||||
* are disabled.
|
||||
*
|
||||
* The default value is empty.
|
||||
*/
|
||||
pj_str_t server;
|
||||
|
||||
/**
|
||||
* The port number of the STUN server, when \a server
|
||||
* field specifies a hostname rather than domain name. This
|
||||
* field should also be set even when the \a server
|
||||
* specifies a domain name, to allow DNS SRV resolution
|
||||
* to fallback to DNS A/AAAA resolution when the DNS SRV
|
||||
* resolution fails.
|
||||
*
|
||||
* The default value is PJ_STUN_PORT.
|
||||
*/
|
||||
pj_uint16_t port;
|
||||
|
||||
} stun;
|
||||
|
||||
/**
|
||||
* The ICE session candidate ID after this candidate has been registered
|
||||
* to an ICE session. Before ICE session is created, or after ICE
|
||||
* session has been destroyed, the value will be -1.
|
||||
* TURN specific settings.
|
||||
*/
|
||||
int ice_cand_id;
|
||||
struct {
|
||||
/**
|
||||
* Specify the TURN server domain or hostname or IP address.
|
||||
* If DNS SRV resolution is required, application must fill
|
||||
* in this setting with the domain name of the TURN server
|
||||
* and set the resolver instance in the \a resolver field.
|
||||
* Otherwise if the \a resolver setting is not set, this
|
||||
* field will be resolved with hostname resolution and in
|
||||
* this case the \a port field must be set.
|
||||
*
|
||||
* The \a port field should also be set even when DNS SRV
|
||||
* resolution is used, in case the DNS SRV resolution fails.
|
||||
*
|
||||
* When this field is empty, relay candidate will not be
|
||||
* created.
|
||||
*
|
||||
* The default value is empty.
|
||||
*/
|
||||
pj_str_t server;
|
||||
|
||||
/**
|
||||
* Local preference value, which typically is 65535.
|
||||
*/
|
||||
pj_uint16_t local_pref;
|
||||
/**
|
||||
* The port number of the TURN server, when \a server
|
||||
* field specifies a hostname rather than domain name. This
|
||||
* field should also be set even when the \a server
|
||||
* specifies a domain name, to allow DNS SRV resolution
|
||||
* to fallback to DNS A/AAAA resolution when the DNS SRV
|
||||
* resolution fails.
|
||||
*
|
||||
* Default is zero.
|
||||
*/
|
||||
pj_uint16_t port;
|
||||
|
||||
/**
|
||||
* Foundation associated with this candidate, which value normally will be
|
||||
* calculated by the function.
|
||||
*/
|
||||
pj_str_t foundation;
|
||||
/**
|
||||
* Type of connection to the TURN server.
|
||||
*
|
||||
* Default is PJ_TURN_TP_UDP.
|
||||
*/
|
||||
pj_turn_tp_type conn_type;
|
||||
|
||||
} pj_ice_strans_cand;
|
||||
/**
|
||||
* Credential to be used for the TURN session. This setting
|
||||
* is mandatory.
|
||||
*
|
||||
* Default is to have no credential.
|
||||
*/
|
||||
pj_stun_auth_cred auth_cred;
|
||||
|
||||
/**
|
||||
* Optional TURN Allocate parameter. The default value will be
|
||||
* initialized by #pj_turn_alloc_param_default().
|
||||
*/
|
||||
pj_turn_alloc_param alloc_param;
|
||||
|
||||
} turn;
|
||||
|
||||
} pj_ice_strans_cfg;
|
||||
|
||||
|
||||
/**
|
||||
* This structure describes an ICE stream transport component. A component
|
||||
* in ICE stream transport typically corresponds to a single socket created
|
||||
* for this component, and bound to a specific transport address. This
|
||||
* component may have multiple alias addresses, for example one alias
|
||||
* address for each interfaces in multi-homed host, another for server
|
||||
* reflexive alias, and another for relayed alias. For each transport
|
||||
* address alias, an ICE stream transport candidate (#pj_ice_strans_cand) will
|
||||
* be created, and these candidates will eventually registered to the ICE
|
||||
* session.
|
||||
*/
|
||||
typedef struct pj_ice_strans_comp
|
||||
{
|
||||
pj_ice_strans *ice_st; /**< ICE stream transport. */
|
||||
unsigned comp_id; /**< Component ID. */
|
||||
pj_uint32_t options; /**< Option flags. */
|
||||
pj_sock_t sock; /**< Socket descriptor. */
|
||||
|
||||
pj_stun_session *stun_sess; /**< STUN session. */
|
||||
pj_uint8_t ka_tsx_id[12]; /**< ID for keep STUN alives */
|
||||
|
||||
pj_sockaddr local_addr; /**< Local/base address. */
|
||||
|
||||
unsigned pending_cnt; /**< Pending resolution cnt. */
|
||||
pj_status_t last_status; /**< Last status. */
|
||||
|
||||
unsigned cand_cnt; /**< # of candidates/aliaes. */
|
||||
pj_ice_strans_cand cand_list[PJ_ICE_ST_MAX_CAND]; /**< Cand array */
|
||||
int default_cand; /**< Default candidate selected */
|
||||
|
||||
pj_ioqueue_key_t *key; /**< ioqueue key. */
|
||||
pj_uint8_t pkt[1500]; /**< Incoming packet buffer. */
|
||||
pj_ioqueue_op_key_t read_op; /**< ioqueue read operation key */
|
||||
pj_ioqueue_op_key_t write_op; /**< ioqueue write op. key */
|
||||
pj_sockaddr src_addr; /**< source packet address buf. */
|
||||
int src_addr_len; /**< length of src addr. buf. */
|
||||
|
||||
} pj_ice_strans_comp;
|
||||
|
||||
|
||||
/**
|
||||
* This structure represents the ICE stream transport.
|
||||
*/
|
||||
struct pj_ice_strans
|
||||
{
|
||||
char obj_name[PJ_MAX_OBJ_NAME]; /**< Log ID. */
|
||||
|
||||
pj_pool_t *pool; /**< Pool used by this object. */
|
||||
void *user_data; /**< Application data. */
|
||||
pj_stun_config stun_cfg; /**< STUN settings. */
|
||||
pj_ice_strans_cb cb; /**< Application callback. */
|
||||
|
||||
pj_ice_sess *ice; /**< ICE session. */
|
||||
|
||||
unsigned comp_cnt; /**< Number of components. */
|
||||
pj_ice_strans_comp **comp; /**< Components array. */
|
||||
|
||||
pj_dns_resolver *resolver; /**< The resolver instance. */
|
||||
pj_bool_t has_rjob; /**< Has pending resolve? */
|
||||
pj_sockaddr_in stun_srv; /**< STUN server address. */
|
||||
pj_sockaddr_in turn_srv; /**< TURN server address. */
|
||||
|
||||
pj_timer_entry ka_timer; /**< STUN keep-alive timer. */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create the ICE stream transport containing the specified number of
|
||||
* components. After the ICE stream transport is created, application
|
||||
* may initialize the STUN server settings, and after that it has to
|
||||
* initialize each components by calling #pj_ice_strans_create_comp()
|
||||
* function.
|
||||
/**
|
||||
* Initialize ICE transport configuration with default values.
|
||||
*
|
||||
* @param cfg The configuration to be initialized.
|
||||
*/
|
||||
PJ_DECL(void) pj_ice_strans_cfg_default(pj_ice_strans_cfg *cfg);
|
||||
|
||||
|
||||
/**
|
||||
* Copy configuration.
|
||||
*
|
||||
* @param pool Pool.
|
||||
* @param dst Destination.
|
||||
* @param src Source.
|
||||
*/
|
||||
PJ_DECL(void) pj_ice_strans_cfg_copy(pj_pool_t *pool,
|
||||
pj_ice_strans_cfg *dst,
|
||||
const pj_ice_strans_cfg *src);
|
||||
|
||||
|
||||
/**
|
||||
* Create and initialize the ICE stream transport with the specified
|
||||
* parameters.
|
||||
*
|
||||
* @param stun_cfg The STUN settings.
|
||||
* @param name Optional name for logging identification.
|
||||
* @param cfg Configuration.
|
||||
* @param comp_cnt Number of components.
|
||||
* @param user_data Arbitrary user data to be associated with this
|
||||
* ICE stream transport.
|
||||
|
@ -399,8 +297,8 @@ struct pj_ice_strans
|
|||
* @return PJ_SUCCESS if ICE stream transport is created
|
||||
* successfully.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_ice_strans_create(pj_stun_config *stun_cfg,
|
||||
const char *name,
|
||||
PJ_DECL(pj_status_t) pj_ice_strans_create(const char *name,
|
||||
const pj_ice_strans_cfg *cfg,
|
||||
unsigned comp_cnt,
|
||||
void *user_data,
|
||||
const pj_ice_strans_cb *cb,
|
||||
|
@ -419,133 +317,24 @@ PJ_DECL(pj_status_t) pj_ice_strans_destroy(pj_ice_strans *ice_st);
|
|||
|
||||
|
||||
/**
|
||||
* Set the domain to be used when resolving the STUN servers. If application
|
||||
* wants to utillize STUN, then STUN server must be specified, either by
|
||||
* calling this function or by calling #pj_ice_strans_set_stun_srv().
|
||||
*
|
||||
* If application calls this function, then the STUN/TURN servers will
|
||||
* be resolved by querying DNS SRV records for the specified domain.
|
||||
*
|
||||
* @param ice_st The ICE stream transport.
|
||||
* @param resolver The resolver instance that will be used to
|
||||
* resolve the STUN/TURN servers.
|
||||
* @param domain The target domain.
|
||||
*
|
||||
* @return PJ_SUCCESS if DNS SRV resolution job can be
|
||||
* started. The resolution process itself will
|
||||
* complete asynchronously.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_ice_strans_set_stun_domain(pj_ice_strans *ice_st,
|
||||
pj_dns_resolver *resolver,
|
||||
const pj_str_t *domain);
|
||||
|
||||
/**
|
||||
* Set the STUN and TURN server addresses. If application
|
||||
* wants to utillize STUN, then STUN server must be specified, either by
|
||||
* calling this function or by calling #pj_ice_strans_set_stun_domain().
|
||||
*
|
||||
* With this function, the STUN and TURN server addresses will be
|
||||
* assigned immediately, that is no DNS resolution will need to be
|
||||
* performed.
|
||||
*
|
||||
* @param ice_st The ICE stream transport.
|
||||
* @param stun_srv The STUN server address, or NULL if STUN
|
||||
* reflexive candidate is not to be used.
|
||||
* @param turn_srv The TURN server address, or NULL if STUN
|
||||
* relay candidate is not to be used.
|
||||
*
|
||||
* @return PJ_SUCCESS, or the appropriate error code.
|
||||
*/
|
||||
PJ_DECL(pj_status_t)
|
||||
pj_ice_strans_set_stun_srv( pj_ice_strans *ice_st,
|
||||
const pj_sockaddr_in *stun_srv,
|
||||
const pj_sockaddr_in *turn_srv);
|
||||
|
||||
/**
|
||||
* Create and initialize the specified component. This function will
|
||||
* instantiate the socket descriptor for this component, optionally
|
||||
* bind the socket to the specified address (or bind to any address/port
|
||||
* if the \a addr parameter is NULL), and start finding all alias
|
||||
* addresses for this socket. For each alias addresses that if finds,
|
||||
* it will add an ICE stream transport candidate for this component.
|
||||
*
|
||||
* After all components have been initialized, application should poll
|
||||
* the #pj_ice_strans_get_comps_status() peridically to check if STUN
|
||||
* server reflexive and relayed candidates have been obtained
|
||||
* successfully.
|
||||
*
|
||||
* @param ice_st The ICE stream transport.
|
||||
* @param comp_id The component ID, which value must be greater than
|
||||
* zero and less than or equal to the number of
|
||||
* components in this ICE stream transport.
|
||||
* @param options Options, see #pj_ice_strans_option.
|
||||
* @param addr Local address where socket will be bound to. This
|
||||
* address will be used as follows:
|
||||
* - if the value is NULL, then socket will be bound
|
||||
* to any available port.
|
||||
* - if the value is not NULL, then if the port number
|
||||
* is not zero, it will used as the starting port
|
||||
* where the socket will be bound to. If bind() to
|
||||
* this port fails, this function will try to bind
|
||||
* to port+2, repeatedly until it succeeded.
|
||||
* If application doesn't want this function to
|
||||
* retry binding the socket to other port, it can
|
||||
* specify PJ_ICE_ST_OPT_NO_PORT_RETRY option.
|
||||
* - if the value is not NULL, then if the address
|
||||
* is not INADDR_ANY, this function will bind the
|
||||
* socket to this particular interface only, and
|
||||
* no other host candidates will be added for this
|
||||
* socket.
|
||||
*
|
||||
*
|
||||
* @return PJ_SUCCESS, or the appropriate error code.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_ice_strans_create_comp(pj_ice_strans *ice_st,
|
||||
unsigned comp_id,
|
||||
pj_uint32_t options,
|
||||
const pj_sockaddr_in *addr);
|
||||
|
||||
/**
|
||||
* Manually add a candidate (transport address alias) for the specified
|
||||
* component. Normally application shouldn't need to use this function,
|
||||
* as candidates will be added automatically when component is created
|
||||
* with #pj_ice_strans_create_comp().
|
||||
*
|
||||
* @param ice_st ICE stream transport.
|
||||
* @param comp_id The component ID.
|
||||
* @param type The candidate type.
|
||||
* @param local_pref The local preference for this candidate
|
||||
* (typically the value is 65535).
|
||||
* @param addr The candidate address.
|
||||
* @param set_default Set to non-zero to make this candidate the
|
||||
* default candidate for this component.
|
||||
*
|
||||
* @return PJ_SUCCESS, or the appropriate error code.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_ice_strans_add_cand(pj_ice_strans *ice_st,
|
||||
unsigned comp_id,
|
||||
pj_ice_cand_type type,
|
||||
pj_uint16_t local_pref,
|
||||
const pj_sockaddr_in *addr,
|
||||
pj_bool_t set_default);
|
||||
|
||||
/**
|
||||
* Get the status of components in the ICE stream transports. Since
|
||||
* some IP address candidates have to be obtained asynchronously (for
|
||||
* example, the STUN reflexive or relay candidate), application can
|
||||
* use this function to know whether the address resolution has
|
||||
* completed.
|
||||
* Get the user data associated with the ICE stream transport.
|
||||
*
|
||||
* @param ice_st The ICE stream transport.
|
||||
*
|
||||
* @return PJ_SUCCESS if all candidates have been resolved
|
||||
* successfully, PJ_EPENDING if transport resolution
|
||||
* is still in progress, or other status on failure.
|
||||
* @return The user data.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_ice_strans_get_comps_status(pj_ice_strans *ice_st);
|
||||
PJ_DECL(void*) pj_ice_strans_get_user_data(pj_ice_strans *ice_st);
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the ICE session in the ICE stream transport.
|
||||
* When application is about to send an offer containing ICE capability,
|
||||
* or when it receives an offer containing ICE capability, it must
|
||||
* call this function to initialize the internal ICE session. This would
|
||||
* register all transport address aliases for each component to the ICE
|
||||
* session as candidates. Then application can enumerate all local
|
||||
* candidates by calling #pj_ice_strans_enum_cands(), and encode these
|
||||
* candidates in the SDP to be sent to remote agent.
|
||||
*
|
||||
* @param ice_st The ICE stream transport.
|
||||
* @param role ICE role.
|
||||
|
@ -560,10 +349,10 @@ PJ_DECL(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
|
|||
const pj_str_t *local_passwd);
|
||||
|
||||
/**
|
||||
* Enumerate the local candidates. This function can only be called
|
||||
* after the ICE session has been created in the ICE stream transport.
|
||||
* Enumerate the local candidates for the specified component.
|
||||
*
|
||||
* @param ice_st The ICE stream transport.
|
||||
* @param comp_id Component ID.
|
||||
* @param count On input, it specifies the maximum number of
|
||||
* elements. On output, it will be filled with
|
||||
* the number of candidates copied to the
|
||||
|
@ -573,38 +362,113 @@ PJ_DECL(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
|
|||
* @return PJ_SUCCESS, or the appropriate error code.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_ice_strans_enum_cands(pj_ice_strans *ice_st,
|
||||
unsigned comp_id,
|
||||
unsigned *count,
|
||||
pj_ice_sess_cand cand[]);
|
||||
|
||||
/**
|
||||
* Start ICE connectivity checks. This function can only be called
|
||||
* after the ICE session has been created in the ICE stream transport.
|
||||
* Get the default candidate for the specified component. When this
|
||||
* function is called before ICE negotiation completes, the default
|
||||
* candidate is selected according to local preference criteria. When
|
||||
* this function is called after ICE negotiation completes, the
|
||||
* default candidate is the candidate that forms the valid pair.
|
||||
*
|
||||
* This function will pair the local and remote candidates to create
|
||||
* check list. Once the check list is created and sorted based on the
|
||||
* priority, ICE periodic checks will be started. This function will
|
||||
* return immediately, and application will be notified about the
|
||||
* connectivity check status in the callback.
|
||||
* @param ice_st The ICE stream transport.
|
||||
* @param comp_id Component ID.
|
||||
* @param cand Pointer to receive the default candidate
|
||||
* information.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_ice_strans_get_def_cand(pj_ice_strans *ice_st,
|
||||
unsigned comp_id,
|
||||
pj_ice_sess_cand *cand);
|
||||
|
||||
/**
|
||||
* Get the current ICE role. ICE session must have been initialized
|
||||
* before this function can be called.
|
||||
*
|
||||
* @param ice_st The ICE stream transport.
|
||||
*
|
||||
* @return Current ICE role.
|
||||
*/
|
||||
PJ_DECL(pj_ice_sess_role) pj_ice_strans_get_role(pj_ice_strans *ice_st);
|
||||
|
||||
|
||||
/**
|
||||
* Change session role. This happens for example when ICE session was
|
||||
* created with controlled role when receiving an offer, but it turns out
|
||||
* that the offer contains "a=ice-lite" attribute when the SDP gets
|
||||
* inspected. ICE session must have been initialized before this function
|
||||
* can be called.
|
||||
*
|
||||
* @param ice_st The ICE stream transport.
|
||||
* @param new_role The new role to be set.
|
||||
*
|
||||
* @return PJ_SUCCESS on success, or the appropriate error.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_ice_strans_change_role(pj_ice_strans *ice_st,
|
||||
pj_ice_sess_role new_role);
|
||||
|
||||
|
||||
/**
|
||||
* Start ICE connectivity checks. This function can only be called
|
||||
* after the ICE session has been created in the ICE stream transport
|
||||
* with #pj_ice_strans_init_ice().
|
||||
*
|
||||
* This function must be called once application has received remote
|
||||
* candidate list (typically from the remote SDP). This function pairs
|
||||
* local candidates with remote candidates, and starts ICE connectivity
|
||||
* checks. The ICE session/transport will then notify the application
|
||||
* via the callback when ICE connectivity checks completes, either
|
||||
* successfully or with failure.
|
||||
*
|
||||
* @param ice_st The ICE stream transport.
|
||||
* @param rem_ufrag Remote ufrag, as seen in the SDP received from
|
||||
* the remote agent.
|
||||
* @param rem_passwd Remote password, as seen in the SDP received from
|
||||
* the remote agent.
|
||||
* @param rem_cand_cnt Number of remote candidates.
|
||||
* @param rem_cand Remote candidate array.
|
||||
* @param rcand_cnt Number of remote candidates in the array.
|
||||
* @param rcand Remote candidates array.
|
||||
*
|
||||
* @return PJ_SUCCESS, or the appropriate error code.
|
||||
*/
|
||||
PJ_DECL(pj_status_t)
|
||||
pj_ice_strans_start_ice( pj_ice_strans *ice_st,
|
||||
const pj_str_t *rem_ufrag,
|
||||
const pj_str_t *rem_passwd,
|
||||
unsigned rem_cand_cnt,
|
||||
const pj_ice_sess_cand rem_cand[]);
|
||||
PJ_DECL(pj_status_t) pj_ice_strans_start_ice(pj_ice_strans *ice_st,
|
||||
const pj_str_t *rem_ufrag,
|
||||
const pj_str_t *rem_passwd,
|
||||
unsigned rcand_cnt,
|
||||
const pj_ice_sess_cand rcand[]);
|
||||
|
||||
/**
|
||||
* Stop and destroy the ICE session inside this media transport.
|
||||
* Retrieve the candidate pair that has been nominated and successfully
|
||||
* checked for the specified component. If ICE negotiation is still in
|
||||
* progress or it has failed, this function will return NULL.
|
||||
*
|
||||
* @param ice_st The ICE stream transport.
|
||||
* @param comp_id Component ID.
|
||||
*
|
||||
* @return The valid pair as ICE checklist structure if the
|
||||
* pair exist.
|
||||
*/
|
||||
PJ_DECL(const pj_ice_sess_check*)
|
||||
pj_ice_strans_get_valid_pair(const pj_ice_strans *ice_st,
|
||||
unsigned comp_id);
|
||||
|
||||
/**
|
||||
* Stop and destroy the ICE session inside this media transport. Application
|
||||
* needs to call this function once the media session is over (the call has
|
||||
* been disconnected).
|
||||
*
|
||||
* Application MAY reuse this ICE stream transport for subsequent calls.
|
||||
* In this case, it must call #pj_ice_strans_stop_ice() when the call is
|
||||
* disconnected, and reinitialize the ICE stream transport for subsequent
|
||||
* call with #pj_ice_strans_init_ice()/#pj_ice_strans_start_ice(). In this
|
||||
* case, the ICE stream transport will maintain the internal sockets and
|
||||
* continue to send STUN keep-alive packets and TURN Refresh request to
|
||||
* keep the NAT binding/TURN allocation open and to detect change in STUN
|
||||
* mapped address.
|
||||
*
|
||||
* If application does not want to reuse the ICE stream transport for
|
||||
* subsequent calls, it must call #pj_ice_strans_destroy() to destroy the
|
||||
* ICE stream transport altogether.
|
||||
*
|
||||
* @param ice_st The ICE stream transport.
|
||||
*
|
||||
|
@ -614,11 +478,16 @@ PJ_DECL(pj_status_t) pj_ice_strans_stop_ice(pj_ice_strans *ice_st);
|
|||
|
||||
|
||||
/**
|
||||
* Send outgoing packet using this transport. If ICE checks have not
|
||||
* produced a valid check for the specified component ID, this function
|
||||
* send to the destination address. Otherwise it will send the packet to
|
||||
* remote destination using the nominated local candidate as have been checked
|
||||
* previously.
|
||||
* Send outgoing packet using this transport.
|
||||
* Application can send data (normally RTP or RTCP packets) at any time
|
||||
* by calling this function. This function takes a destination
|
||||
* address as one of the arguments, and this destination address should
|
||||
* be taken from the default transport address of the component (that is
|
||||
* the address in SDP c= and m= lines, or in a=rtcp attribute).
|
||||
* If ICE negotiation is in progress, this function will send the data
|
||||
* to the destination address. Otherwise if ICE negotiation has completed
|
||||
* successfully, this function will send the data to the nominated remote
|
||||
* address, as negotiated by ICE.
|
||||
*
|
||||
* @param ice_st The ICE stream transport.
|
||||
* @param comp_id Component ID.
|
||||
|
|
|
@ -32,7 +32,6 @@ PJ_BEGIN_DECL
|
|||
/**
|
||||
* @defgroup PJNATH_NAT_DETECT NAT Classification/Detection Tool
|
||||
* @brief NAT Classification/Detection Tool
|
||||
* @ingroup PJNATH_ICE
|
||||
* @{
|
||||
*
|
||||
* This module provides one function to perform NAT classification and
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
*/
|
||||
|
||||
#include <pjnath/stun_msg.h>
|
||||
#include <pj/assert.h>
|
||||
#include <pj/errno.h>
|
||||
#include <pj/string.h>
|
||||
|
||||
|
||||
|
@ -102,6 +104,17 @@ PJ_INLINE(void) pj_stun_config_init(pj_stun_config *cfg,
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check that STUN config is valid.
|
||||
*/
|
||||
PJ_INLINE(pj_status_t) pj_stun_config_check_valid(const pj_stun_config *cfg)
|
||||
{
|
||||
PJ_ASSERT_RETURN(cfg->ioqueue && cfg->pf && cfg->timer_heap &&
|
||||
cfg->rto_msec && cfg->res_cache_msec, PJ_EINVAL);
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -34,8 +34,8 @@ PJ_BEGIN_DECL
|
|||
/* **************************************************************************/
|
||||
/**
|
||||
* @defgroup PJNATH_STUN_MSG STUN Message Representation and Parsing
|
||||
* @brief Low-level representation and parsing of STUN messages.
|
||||
* @ingroup PJNATH_STUN
|
||||
* @brief Low-level representation and parsing of STUN messages.
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
@ -955,9 +955,8 @@ typedef struct pj_stun_uint_attr pj_stun_req_addr_type;
|
|||
/**
|
||||
* This describes the TURN REQUESTED-PROPS attribute, encoded as
|
||||
* STUN 32bit integer attribute. Few macros are provided to manipulate
|
||||
* the values in this attribute: #PJ_STUN_GET_RPP_BITS(),
|
||||
* #PJ_STUN_SET_RPP_BITS(), #PJ_STUN_GET_RPP_PORT(), and
|
||||
* #PJ_STUN_SET_RPP_PORT().
|
||||
* the values in this attribute: #PJ_STUN_GET_PROP_TYPE(), and
|
||||
* #PJ_STUN_SET_PROP_TYPE().
|
||||
*
|
||||
* This attribute allows the client to request certain properties for
|
||||
* the relayed transport address that is allocated by the server. The
|
||||
|
@ -1164,7 +1163,7 @@ enum pj_stun_decode_options
|
|||
* Disable FINGERPRINT verification. This option can be used when calling
|
||||
* #pj_stun_msg_check() and #pj_stun_msg_decode() to disable the
|
||||
* verification of FINGERPRINT, for example when the STUN usage says when
|
||||
* FINGERPRINT mechanism shall not * be used.
|
||||
* FINGERPRINT mechanism shall not be used.
|
||||
*/
|
||||
PJ_STUN_NO_FINGERPRINT_CHECK = 8
|
||||
};
|
||||
|
@ -1292,7 +1291,7 @@ PJ_DECL(pj_status_t) pj_stun_msg_add_attr(pj_stun_msg *msg,
|
|||
* value, if these attributes are present in the message.
|
||||
*
|
||||
* If application wants to apply credential to the message, it MUST
|
||||
* include a blank MESSAGE-INTEGRITY attribute in the message, as the
|
||||
* include a blank MESSAGE-INTEGRITY attribute in the message as the
|
||||
* last attribute or the attribute before FINGERPRINT. This function will
|
||||
* calculate the HMAC digest from the message using the supplied key in
|
||||
* the parameter. The key should be set to the password if short term
|
||||
|
@ -1320,10 +1319,10 @@ PJ_DECL(pj_status_t) pj_stun_msg_add_attr(pj_stun_msg *msg,
|
|||
*/
|
||||
PJ_DECL(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
|
||||
pj_uint8_t *pkt_buf,
|
||||
unsigned buf_size,
|
||||
pj_size_t buf_size,
|
||||
unsigned options,
|
||||
const pj_str_t *key,
|
||||
unsigned *p_msg_len);
|
||||
pj_size_t *p_msg_len);
|
||||
|
||||
/**
|
||||
* Check that the PDU is potentially a valid STUN message. This function
|
||||
|
@ -1345,7 +1344,7 @@ PJ_DECL(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
|
|||
* message.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_stun_msg_check(const pj_uint8_t *pdu,
|
||||
unsigned pdu_len, unsigned options);
|
||||
pj_size_t pdu_len, unsigned options);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -1371,10 +1370,10 @@ PJ_DECL(pj_status_t) pj_stun_msg_check(const pj_uint8_t *pdu,
|
|||
*/
|
||||
PJ_DECL(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
|
||||
const pj_uint8_t *pdu,
|
||||
unsigned pdu_len,
|
||||
pj_size_t pdu_len,
|
||||
unsigned options,
|
||||
pj_stun_msg **p_msg,
|
||||
unsigned *p_parsed_len,
|
||||
pj_size_t *p_parsed_len,
|
||||
pj_stun_msg **p_response);
|
||||
|
||||
/**
|
||||
|
|
|
@ -213,6 +213,7 @@ struct pj_stun_rx_data
|
|||
*/
|
||||
struct pj_stun_tx_data
|
||||
{
|
||||
/** PJLIB list interface */
|
||||
PJ_DECL_LIST_MEMBER(struct pj_stun_tx_data);
|
||||
|
||||
pj_pool_t *pool; /**< Pool. */
|
||||
|
@ -239,6 +240,21 @@ struct pj_stun_tx_data
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* These are the flags to control the message logging in the STUN session.
|
||||
*/
|
||||
typedef enum pj_stun_sess_msg_log_flag
|
||||
{
|
||||
PJ_STUN_SESS_LOG_TX_REQ=1, /**< Log outgoing STUN requests. */
|
||||
PJ_STUN_SESS_LOG_TX_RES=2, /**< Log outgoing STUN responses. */
|
||||
PJ_STUN_SESS_LOG_TX_IND=4, /**< Log outgoing STUN indications. */
|
||||
|
||||
PJ_STUN_SESS_LOG_RX_REQ=8, /**< Log incoming STUN requests. */
|
||||
PJ_STUN_SESS_LOG_RX_RES=16, /**< Log incoming STUN responses */
|
||||
PJ_STUN_SESS_LOG_RX_IND=32 /**< Log incoming STUN indications */
|
||||
} pj_stun_sess_msg_log_flag;
|
||||
|
||||
|
||||
/**
|
||||
* Create a STUN session.
|
||||
*
|
||||
|
@ -258,11 +274,16 @@ PJ_DECL(pj_status_t) pj_stun_session_create(pj_stun_config *cfg,
|
|||
pj_stun_session **p_sess);
|
||||
|
||||
/**
|
||||
* Destroy the STUN session.
|
||||
* Destroy the STUN session and all objects created in the context of
|
||||
* this session.
|
||||
*
|
||||
* @param sess The STUN session instance.
|
||||
*
|
||||
* @return PJ_SUCCESS on success, or the appropriate error code.
|
||||
* This function will return PJ_EPENDING if the operation
|
||||
* cannot be performed immediately because callbacks are
|
||||
* being called; in this case the session will be destroyed
|
||||
* as soon as the last callback returns.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess);
|
||||
|
||||
|
@ -333,6 +354,14 @@ PJ_DECL(pj_status_t) pj_stun_session_set_server_name(pj_stun_session *sess,
|
|||
PJ_DECL(pj_status_t) pj_stun_session_set_credential(pj_stun_session *sess,
|
||||
pj_stun_auth_type auth_type,
|
||||
const pj_stun_auth_cred *cred);
|
||||
/**
|
||||
* Configure message logging. By default all flags are enabled.
|
||||
*
|
||||
* @param sess The STUN session instance.
|
||||
* @param flags Bitmask combination of #pj_stun_sess_msg_log_flag
|
||||
*/
|
||||
PJ_DECL(void) pj_stun_session_set_log(pj_stun_session *sess,
|
||||
unsigned flags);
|
||||
|
||||
/**
|
||||
* Create a STUN request message. After the message has been successfully
|
||||
|
@ -381,7 +410,7 @@ PJ_DECL(pj_status_t) pj_stun_session_create_ind(pj_stun_session *sess,
|
|||
* call.
|
||||
*
|
||||
* @param sess The STUN session instance.
|
||||
* @param req The STUN request where the response is to be created.
|
||||
* @param rdata The STUN request where the response is to be created.
|
||||
* @param err_code Error code to be set in the response, if error response
|
||||
* is to be created, according to pj_stun_status enumeration.
|
||||
* This argument MUST be zero if successful response is
|
||||
|
@ -432,6 +461,9 @@ PJ_DECL(pj_status_t) pj_stun_session_create_res(pj_stun_session *sess,
|
|||
* be sent.
|
||||
*
|
||||
* @return PJ_SUCCESS on success, or the appropriate error code.
|
||||
* This function will return PJNATH_ESTUNDESTROYED if
|
||||
* application has destroyed the session in
|
||||
* \a on_send_msg() callback.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_stun_session_send_msg(pj_stun_session *sess,
|
||||
void *token,
|
||||
|
@ -449,7 +481,7 @@ PJ_DECL(pj_status_t) pj_stun_session_send_msg(pj_stun_session *sess,
|
|||
*
|
||||
* @param sess The STUN session instance.
|
||||
* @param rdata The STUN request message to be responded.
|
||||
* @param err_code Error code to be set in the response, if error response
|
||||
* @param code Error code to be set in the response, if error response
|
||||
* is to be created, according to pj_stun_status enumeration.
|
||||
* This argument MUST be zero if successful response is
|
||||
* to be created.
|
||||
|
@ -472,6 +504,9 @@ PJ_DECL(pj_status_t) pj_stun_session_send_msg(pj_stun_session *sess,
|
|||
* @param addr_len Address length.
|
||||
*
|
||||
* @return PJ_SUCCESS on success, or the appropriate error code.
|
||||
* This function will return PJNATH_ESTUNDESTROYED if
|
||||
* application has destroyed the session in
|
||||
* \a on_send_msg() callback.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_stun_session_respond(pj_stun_session *sess,
|
||||
const pj_stun_rx_data *rdata,
|
||||
|
@ -496,6 +531,9 @@ PJ_DECL(pj_status_t) pj_stun_session_respond(pj_stun_session *sess,
|
|||
* callback. This error status MUST NOT be PJ_SUCCESS.
|
||||
*
|
||||
* @return PJ_SUCCESS if transaction is successfully cancelled.
|
||||
* This function will return PJNATH_ESTUNDESTROYED if
|
||||
* application has destroyed the session in
|
||||
* \a on_request_complete() callback.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_stun_session_cancel_req(pj_stun_session *sess,
|
||||
pj_stun_tx_data *tdata,
|
||||
|
@ -511,6 +549,9 @@ PJ_DECL(pj_status_t) pj_stun_session_cancel_req(pj_stun_session *sess,
|
|||
* @param tdata The request message previously sent.
|
||||
*
|
||||
* @return PJ_SUCCESS on success, or the appropriate error.
|
||||
* This function will return PJNATH_ESTUNDESTROYED if
|
||||
* application has destroyed the session in \a on_send_msg()
|
||||
* callback.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_stun_session_retransmit_req(pj_stun_session *sess,
|
||||
pj_stun_tx_data *tdata);
|
||||
|
@ -548,6 +589,9 @@ PJ_DECL(pj_status_t) pj_stun_session_retransmit_req(pj_stun_session *sess,
|
|||
* @param src_addr_len Length of the source address.
|
||||
*
|
||||
* @return PJ_SUCCESS on success, or the appropriate error code.
|
||||
* This function will return PJNATH_ESTUNDESTROYED if
|
||||
* application has destroyed the session in one of the
|
||||
* callback.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
|
||||
const void *packet,
|
||||
|
|
|
@ -0,0 +1,403 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
* Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef __PJNATH_STUN_SOCK_H__
|
||||
#define __PJNATH_STUN_SOCK_H__
|
||||
|
||||
/**
|
||||
* @file stun_sock.h
|
||||
* @brief STUN aware socket transport
|
||||
*/
|
||||
#include <pjnath/stun_config.h>
|
||||
#include <pjlib-util/resolver.h>
|
||||
#include <pj/ioqueue.h>
|
||||
#include <pj/sock.h>
|
||||
|
||||
|
||||
PJ_BEGIN_DECL
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup PJNATH_STUN_SOCK STUN aware socket transport
|
||||
* @brief STUN aware socket transport
|
||||
* @ingroup PJNATH_STUN
|
||||
* @{
|
||||
* The STUN transport provides asynchronous UDP like socket transport
|
||||
* with the additional capability to query the publicly mapped transport
|
||||
* address (using STUN resolution), to refresh the NAT binding, and to
|
||||
* demultiplex internal STUN messages from application data (the
|
||||
* application data may be a STUN message as well).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Opaque type to represent a STUN transport.
|
||||
*/
|
||||
typedef struct pj_stun_sock pj_stun_sock;
|
||||
|
||||
/**
|
||||
* Types of operation being reported in \a on_status() callback of
|
||||
* pj_stun_sock_cb. Application may retrieve the string representation
|
||||
* of these constants with pj_stun_sock_op_name().
|
||||
*/
|
||||
typedef enum pj_stun_sock_op
|
||||
{
|
||||
/**
|
||||
* Asynchronous DNS resolution.
|
||||
*/
|
||||
PJ_STUN_SOCK_DNS_OP = 1,
|
||||
|
||||
/**
|
||||
* Initial STUN Binding request.
|
||||
*/
|
||||
PJ_STUN_SOCK_BINDING_OP,
|
||||
|
||||
/**
|
||||
* Subsequent STUN Binding request for keeping the binding
|
||||
* alive.
|
||||
*/
|
||||
PJ_STUN_SOCK_KEEP_ALIVE_OP,
|
||||
|
||||
} pj_stun_sock_op;
|
||||
|
||||
|
||||
/**
|
||||
* This structure contains callbacks that will be called by the STUN
|
||||
* transport to notify application about various events.
|
||||
*/
|
||||
typedef struct pj_stun_sock_cb
|
||||
{
|
||||
/**
|
||||
* Notification when incoming packet has been received.
|
||||
*
|
||||
* @param stun_sock The STUN transport.
|
||||
* @param data The packet.
|
||||
* @param data_len Length of the packet.
|
||||
* @param src_addr The source address of the packet.
|
||||
* @param addr_len The length of the source address.
|
||||
*
|
||||
* @return Application should normally return PJ_TRUE to let
|
||||
* the STUN transport continue its operation. However
|
||||
* it must return PJ_FALSE if it has destroyed the
|
||||
* STUN transport in this callback.
|
||||
*/
|
||||
pj_bool_t (*on_rx_data)(pj_stun_sock *stun_sock,
|
||||
void *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
unsigned addr_len);
|
||||
|
||||
/**
|
||||
* Notifification when asynchronous send operation has completed.
|
||||
*
|
||||
* @param stun_sock The STUN transport.
|
||||
* @param send_key The send operation key that was given in
|
||||
* #pj_stun_sock_sendto().
|
||||
* @param sent If value is positive non-zero it indicates the
|
||||
* number of data sent. When the value is negative,
|
||||
* it contains the error code which can be retrieved
|
||||
* by negating the value (i.e. status=-sent).
|
||||
*
|
||||
* @return Application should normally return PJ_TRUE to let
|
||||
* the STUN transport continue its operation. However
|
||||
* it must return PJ_FALSE if it has destroyed the
|
||||
* STUN transport in this callback.
|
||||
*/
|
||||
pj_bool_t (*on_data_sent)(pj_stun_sock *stun_sock,
|
||||
pj_ioqueue_op_key_t *send_key,
|
||||
pj_ssize_t sent);
|
||||
|
||||
/**
|
||||
* Notification when the status of the STUN transport has changed. This
|
||||
* callback may be called for the following conditions:
|
||||
* - the first time the publicly mapped address has been resolved from
|
||||
* the STUN server, this callback will be called with \a op argument
|
||||
* set to PJ_STUN_SOCK_BINDING_OP \a status argument set to
|
||||
* PJ_SUCCESS.
|
||||
* - anytime when the transport has detected that the publicly mapped
|
||||
* address has changed, this callback will be called with \a op
|
||||
* argument set to PJ_STUN_SOCK_KEEP_ALIVE_OP and \a status
|
||||
* argument set to PJ_SUCCESS. On this case and the case above,
|
||||
* application will get the resolved public address in the
|
||||
* #pj_stun_sock_info structure.
|
||||
* - for any terminal error (such as STUN time-out, DNS resolution
|
||||
* failure, or keep-alive failure), this callback will be called
|
||||
* with the \a status argument set to non-PJ_SUCCESS.
|
||||
*
|
||||
* @param stun_sock The STUN transport.
|
||||
* @param op The operation that triggers the callback.
|
||||
* @param status The status.
|
||||
*
|
||||
* @return Must return PJ_FALSE if it has destroyed the
|
||||
* STUN transport in this callback. Application should
|
||||
* normally destroy the socket and return PJ_FALSE
|
||||
* upon encountering terminal error, otherwise it
|
||||
* should return PJ_TRUE to let the STUN socket operation
|
||||
* continues.
|
||||
*/
|
||||
pj_bool_t (*on_status)(pj_stun_sock *stun_sock,
|
||||
pj_stun_sock_op op,
|
||||
pj_status_t status);
|
||||
|
||||
} pj_stun_sock_cb;
|
||||
|
||||
|
||||
/**
|
||||
* This structure contains information about the STUN transport. Application
|
||||
* may query this information by calling #pj_stun_sock_get_info().
|
||||
*/
|
||||
typedef struct pj_stun_sock_info
|
||||
{
|
||||
/**
|
||||
* The bound address of the socket.
|
||||
*/
|
||||
pj_sockaddr bound_addr;
|
||||
|
||||
/**
|
||||
* IP address of the STUN server.
|
||||
*/
|
||||
pj_sockaddr srv_addr;
|
||||
|
||||
/**
|
||||
* The publicly mapped address. It may contain zero address when the
|
||||
* mapped address has not been resolved. Application may query whether
|
||||
* this field contains valid address with pj_sockaddr_has_addr().
|
||||
*/
|
||||
pj_sockaddr mapped_addr;
|
||||
|
||||
/**
|
||||
* Number of interface address aliases. The interface address aliases
|
||||
* are list of all interface addresses in this host.
|
||||
*/
|
||||
unsigned alias_cnt;
|
||||
|
||||
/**
|
||||
* Array of interface address aliases.
|
||||
*/
|
||||
pj_sockaddr aliases[PJ_ICE_ST_MAX_CAND];
|
||||
|
||||
} pj_stun_sock_info;
|
||||
|
||||
|
||||
/**
|
||||
* This describe the settings to be given to the STUN transport during its
|
||||
* creation. Application should initialize this structure by calling
|
||||
* #pj_stun_sock_cfg_default().
|
||||
*/
|
||||
typedef struct pj_stun_sock_cfg
|
||||
{
|
||||
/**
|
||||
* Packet buffer size. Default value is PJ_STUN_SOCK_PKT_LEN.
|
||||
*/
|
||||
unsigned max_pkt_size;
|
||||
|
||||
/**
|
||||
* Specify the number of simultaneous asynchronous read operations to
|
||||
* be invoked to the ioqueue. Having more than one read operations will
|
||||
* increase performance on multiprocessor systems since the application
|
||||
* will be able to process more than one incoming packets simultaneously.
|
||||
* Default value is 1.
|
||||
*/
|
||||
unsigned async_cnt;
|
||||
|
||||
/**
|
||||
* Specify the interface where the socket should be bound to. If the
|
||||
* address is zero, socket will be bound to INADDR_ANY. If the address
|
||||
* is non-zero, socket will be bound to this address only, and the
|
||||
* transport will have only one address alias (the \a alias_cnt field
|
||||
* in #pj_stun_sock_info structure.
|
||||
*/
|
||||
pj_sockaddr bound_addr;
|
||||
|
||||
/**
|
||||
* Specify the STUN keep-alive duration, in seconds. The STUN transport
|
||||
* does keep-alive by sending STUN Binding request to the STUN server.
|
||||
* If this value is zero, the PJ_STUN_KEEP_ALIVE_SEC value will be used.
|
||||
* If the value is negative, it will disable STUN keep-alive.
|
||||
*/
|
||||
int ka_interval;
|
||||
|
||||
} pj_stun_sock_cfg;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the name representing the specified operation.
|
||||
*/
|
||||
PJ_DECL(const char*) pj_stun_sock_op_name(pj_stun_sock_op op);
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the STUN transport setting with its default values.
|
||||
*
|
||||
* @param cfg The STUN transport config.
|
||||
*/
|
||||
PJ_DECL(void) pj_stun_sock_cfg_default(pj_stun_sock_cfg *cfg);
|
||||
|
||||
|
||||
/**
|
||||
* Create the STUN transport using the specified configuration. Once
|
||||
* the STUN transport has been create, application should call
|
||||
* #pj_stun_sock_start() to start the transport.
|
||||
*
|
||||
* @param stun_cfg The STUN configuration which contains among other
|
||||
* things the ioqueue and timer heap instance for
|
||||
* the operation of this transport.
|
||||
* @param af Address family of socket. Currently pj_AF_INET()
|
||||
* and pj_AF_INET6() are supported.
|
||||
* @param name Optional name to be given to this transport to
|
||||
* assist debugging.
|
||||
* @param cb Callback to receive events/data from the transport.
|
||||
* @param cfg Optional transport settings.
|
||||
* @param user_data Arbitrary application data to be associated with
|
||||
* this transport.
|
||||
* @param p_sock Pointer to receive the created transport instance.
|
||||
*
|
||||
* @restun PJ_SUCCESS if the operation has been successful,
|
||||
* or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_stun_sock_create(pj_stun_config *stun_cfg,
|
||||
const char *name,
|
||||
int af,
|
||||
const pj_stun_sock_cb *cb,
|
||||
const pj_stun_sock_cfg *cfg,
|
||||
void *user_data,
|
||||
pj_stun_sock **p_sock);
|
||||
|
||||
|
||||
/**
|
||||
* Start the STUN transport. This will start the DNS SRV resolution for
|
||||
* the STUN server (if desired), and once the server is resolved, STUN
|
||||
* Binding request will be sent to resolve the publicly mapped address.
|
||||
* Once the initial STUN Binding response is received, the keep-alive
|
||||
* timer will be started.
|
||||
*
|
||||
* @param stun_sock The STUN transport instance.
|
||||
* @param domain The domain, hostname, or IP address of the TURN
|
||||
* server. When this parameter contains domain name,
|
||||
* the \a resolver parameter must be set to activate
|
||||
* DNS SRV resolution.
|
||||
* @param default_port The default STUN port number to use when DNS SRV
|
||||
* resolution is not used. If DNS SRV resolution is
|
||||
* used, the server port number will be set from the
|
||||
* DNS SRV records. The recommended value for this
|
||||
* parameter is PJ_STUN_PORT.
|
||||
* @param resolver If this parameter is not NULL, then the \a domain
|
||||
* parameter will be first resolved with DNS SRV and
|
||||
* then fallback to using DNS A/AAAA resolution when
|
||||
* DNS SRV resolution fails. If this parameter is
|
||||
* NULL, the \a domain parameter will be resolved as
|
||||
* hostname.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successfully
|
||||
* queued, or the appropriate error code on failure.
|
||||
* When this function returns PJ_SUCCESS, the final
|
||||
* result of the allocation process will be notified
|
||||
* to application in \a on_state() callback.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_stun_sock_start(pj_stun_sock *stun_sock,
|
||||
const pj_str_t *domain,
|
||||
pj_uint16_t default_port,
|
||||
pj_dns_resolver *resolver);
|
||||
|
||||
/**
|
||||
* Destroy the STUN transport.
|
||||
*
|
||||
* @param sock The STUN transport socket.
|
||||
*
|
||||
* @restun PJ_SUCCESS if the operation has been successful,
|
||||
* or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_stun_sock_destroy(pj_stun_sock *sock);
|
||||
|
||||
|
||||
/**
|
||||
* Associate a user data with this STUN transport. The user data may then
|
||||
* be retrieved later with #pj_stun_sock_get_user_data().
|
||||
*
|
||||
* @param stun_sock The STUN transport instance.
|
||||
* @param user_data Arbitrary data.
|
||||
*
|
||||
* @restun PJ_SUCCESS if the operation has been successful,
|
||||
* or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_stun_sock_set_user_data(pj_stun_sock *stun_sock,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* Retrieve the previously assigned user data associated with this STUN
|
||||
* transport.
|
||||
*
|
||||
* @param stun_sock The STUN transport instance.
|
||||
*
|
||||
* @restun The user/application data.
|
||||
*/
|
||||
PJ_DECL(void*) pj_stun_sock_get_user_data(pj_stun_sock *stun_sock);
|
||||
|
||||
|
||||
/**
|
||||
* Get the STUN transport info. The transport info contains, among other
|
||||
* things, the allocated relay address.
|
||||
*
|
||||
* @param stun_sock The STUN transport instance.
|
||||
* @param info Pointer to be filled with STUN transport info.
|
||||
*
|
||||
* @restun PJ_SUCCESS if the operation has been successful,
|
||||
* or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_stun_sock_get_info(pj_stun_sock *stun_sock,
|
||||
pj_stun_sock_info *info);
|
||||
|
||||
|
||||
/**
|
||||
* Send a data to the specified address. This function may complete
|
||||
* asynchronously and in this case \a on_data_sent() will be called.
|
||||
*
|
||||
* @param stun_sock The STUN transport instance.
|
||||
* @param op_key Optional send key for sending the packet down to
|
||||
* the ioqueue. This value will be given back to
|
||||
* \a on_data_sent() callback
|
||||
* @param pkt The data/packet to be sent to peer.
|
||||
* @param pkt_len Length of the data.
|
||||
* @param flag pj_ioqueue_sendto() flag.
|
||||
* @param dst_addr The remote address.
|
||||
* @param addr_len Length of the address.
|
||||
*
|
||||
* @return PJ_SUCCESS if data has been sent immediately, or
|
||||
* PJ_EPENDING if data cannot be sent immediately. In
|
||||
* this case the \a on_data_sent() callback will be
|
||||
* called when data is actually sent. Any other return
|
||||
* value indicates error condition.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_stun_sock_sendto(pj_stun_sock *stun_sock,
|
||||
pj_ioqueue_op_key_t *send_key,
|
||||
const void *pkt,
|
||||
unsigned pkt_len,
|
||||
unsigned flag,
|
||||
const pj_sockaddr_t *dst_addr,
|
||||
unsigned addr_len);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
PJ_END_DECL
|
||||
|
||||
|
||||
#endif /* __PJNATH_STUN_SOCK_H__ */
|
||||
|
|
@ -89,7 +89,9 @@ typedef struct pj_stun_tsx_cb
|
|||
* @param pkt_size Size of the STUN packet.
|
||||
*
|
||||
* @return If return value of the callback is not PJ_SUCCESS,
|
||||
* the transaction will fail.
|
||||
* the transaction will fail. Application MUST return
|
||||
* PJNATH_ESTUNDESTROYED if it has destroyed the
|
||||
* transaction in this callback.
|
||||
*/
|
||||
pj_status_t (*on_send_msg)(pj_stun_client_tsx *tsx,
|
||||
const void *stun_pkt,
|
||||
|
@ -161,7 +163,8 @@ pj_stun_client_tsx_schedule_destroy(pj_stun_client_tsx *tsx,
|
|||
*
|
||||
* @param tsx The STUN transaction.
|
||||
*
|
||||
* @return PJ_SUCCESS on success, or the appropriate error code.
|
||||
* @return PJ_SUCCESS on success or PJ_EINVAL if the parameter
|
||||
* is NULL.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_stun_client_tsx_destroy(pj_stun_client_tsx *tsx);
|
||||
|
||||
|
@ -214,7 +217,10 @@ PJ_DECL(void*) pj_stun_client_tsx_get_data(pj_stun_client_tsx *tsx);
|
|||
* @param pkt The STUN packet to send.
|
||||
* @param pkt_len Length of STUN packet.
|
||||
*
|
||||
* @return PJ_SUCCESS on success or the appropriate error code.
|
||||
* @return PJ_SUCCESS on success, or PJNATH_ESTUNDESTROYED
|
||||
* when the user has destroyed the transaction in
|
||||
* \a on_send_msg() callback, or any other error code
|
||||
* as returned by \a on_send_msg() callback.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_stun_client_tsx_send_msg(pj_stun_client_tsx *tsx,
|
||||
pj_bool_t retransmit,
|
||||
|
@ -228,7 +234,10 @@ PJ_DECL(pj_status_t) pj_stun_client_tsx_send_msg(pj_stun_client_tsx *tsx,
|
|||
*
|
||||
* @param tsx The STUN client transaction instance.
|
||||
*
|
||||
* @return PJ_SUCCESS on success or the appropriate error code.
|
||||
* @return PJ_SUCCESS on success, or PJNATH_ESTUNDESTROYED
|
||||
* when the user has destroyed the transaction in
|
||||
* \a on_send_msg() callback, or any other error code
|
||||
* as returned by \a on_send_msg() callback.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_stun_client_tsx_retransmit(pj_stun_client_tsx *tsx);
|
||||
|
||||
|
|
|
@ -29,12 +29,25 @@
|
|||
|
||||
PJ_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* @defgroup PJNATH_TURN TURN Client Library
|
||||
*/
|
||||
|
||||
|
||||
/* **************************************************************************/
|
||||
/**
|
||||
* @defgroup PJNATH_TURN_SESSION TURN client session
|
||||
* @defgroup PJNATH_TURN_SESSION Transport independent TURN client session
|
||||
* @brief Transport independent TURN client session
|
||||
* @ingroup PJNATH_STUN
|
||||
* @ingroup PJNATH_TURN
|
||||
* @{
|
||||
*
|
||||
* This module describes the transport independent TURN client session. This
|
||||
* interface is provided for implementors of a TURN client transport, and
|
||||
* application usually will want to use \ref PJNATH_TURN_SOCK instead.
|
||||
*
|
||||
* The transport independent TURN client session is created to facilitate
|
||||
* the creation of different types of transports between the client and the
|
||||
* TURN server.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -43,18 +56,6 @@ PJ_BEGIN_DECL
|
|||
typedef struct pj_turn_session pj_turn_session;
|
||||
|
||||
|
||||
#define PJ_TURN_INVALID_CHANNEL 0xFFFF
|
||||
#define PJ_TURN_CHANNEL_MIN 0x4000
|
||||
#define PJ_TURN_CHANNEL_MAX 0xFFFE /* inclusive */
|
||||
#define PJ_TURN_NO_TIMEOUT ((long)0x7FFFFFFF)
|
||||
#define PJ_TURN_MAX_PKT_LEN 3000
|
||||
#define PJ_TURN_PERM_TIMEOUT 300 /* Must be greater than REFRESH_SEC_BEFORE */
|
||||
#define PJ_TURN_CHANNEL_TIMEOUT 600 /* Must be greater than REFRESH_SEC_BEFORE */
|
||||
#define PJ_TURN_REFRESH_SEC_BEFORE 60
|
||||
#define PJ_TURN_KEEP_ALIVE_SEC 15
|
||||
#define PJ_TURN_PEER_HTABLE_SIZE 8
|
||||
|
||||
|
||||
/**
|
||||
* TURN transport types, which will be used both to specify the connection
|
||||
* type for reaching TURN server and the type of allocation transport to be
|
||||
|
@ -133,14 +134,21 @@ typedef enum pj_turn_state_t
|
|||
} pj_turn_state_t;
|
||||
|
||||
|
||||
/* ChannelData header */
|
||||
#pragma pack(1)
|
||||
|
||||
/**
|
||||
* This structure ChannelData header. All the fields are in network byte
|
||||
* order when it's on the wire.
|
||||
*/
|
||||
typedef struct pj_turn_channel_data
|
||||
{
|
||||
pj_uint16_t ch_number;
|
||||
pj_uint16_t length;
|
||||
pj_uint16_t ch_number; /**< Channel number. */
|
||||
pj_uint16_t length; /**< Payload length. */
|
||||
} pj_turn_channel_data;
|
||||
|
||||
|
||||
#pragma pack()
|
||||
|
||||
|
||||
/**
|
||||
* Callback to receive events from TURN session.
|
||||
|
@ -151,18 +159,33 @@ typedef struct pj_turn_session_cb
|
|||
* This callback will be called by the TURN session whenever it
|
||||
* needs to send outgoing message. Since the TURN session doesn't
|
||||
* have a socket on its own, this callback must be implemented.
|
||||
*
|
||||
* @param sess The TURN session.
|
||||
* @param pkt The packet/data to be sent.
|
||||
* @param pkt_len Length of the packet/data.
|
||||
* @param dst_addr Destination address of the packet.
|
||||
* @param addr_len Length of the destination address.
|
||||
*
|
||||
* @return The callback should return the status of the
|
||||
* send operation.
|
||||
*/
|
||||
pj_status_t (*on_send_pkt)(pj_turn_session *sess,
|
||||
const pj_uint8_t *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *dst_addr,
|
||||
unsigned dst_addr_len);
|
||||
unsigned addr_len);
|
||||
|
||||
/**
|
||||
* Notification when peer address has been bound successfully to
|
||||
* a channel number.
|
||||
*
|
||||
* This callback is optional.
|
||||
* This callback is optional since the nature of this callback is
|
||||
* for information only.
|
||||
*
|
||||
* @param sess The TURN session.
|
||||
* @param peer_addr The peer address.
|
||||
* @param addr_len Length of the peer address.
|
||||
* @param ch_num The channel number associated with this peer address.
|
||||
*/
|
||||
void (*on_channel_bound)(pj_turn_session *sess,
|
||||
const pj_sockaddr_t *peer_addr,
|
||||
|
@ -173,10 +196,16 @@ typedef struct pj_turn_session_cb
|
|||
* Notification when incoming data has been received, either through
|
||||
* Data indication or ChannelData message from the TURN server.
|
||||
*
|
||||
* This callback is optional.
|
||||
* @param sess The TURN session.
|
||||
* @param pkt The data/payload of the Data Indication or ChannelData
|
||||
* packet.
|
||||
* @param pkt_len Length of the data/payload.
|
||||
* @param peer_addr Peer address where this payload was received by
|
||||
* the TURN server.
|
||||
* @param addr_len Length of the peer address.
|
||||
*/
|
||||
void (*on_rx_data)(pj_turn_session *sess,
|
||||
const pj_uint8_t *pkt,
|
||||
void *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *peer_addr,
|
||||
unsigned addr_len);
|
||||
|
@ -185,26 +214,50 @@ typedef struct pj_turn_session_cb
|
|||
* Notification when TURN session state has changed. Application should
|
||||
* implement this callback at least to know that the TURN session is
|
||||
* going to be destroyed.
|
||||
*
|
||||
* @param sess The TURN session.
|
||||
* @param old_state The previous state of the session.
|
||||
* @param new_state The current state of the session.
|
||||
*/
|
||||
void (*on_state)(pj_turn_session *sess, pj_turn_state_t old_state,
|
||||
void (*on_state)(pj_turn_session *sess,
|
||||
pj_turn_state_t old_state,
|
||||
pj_turn_state_t new_state);
|
||||
|
||||
} pj_turn_session_cb;
|
||||
|
||||
|
||||
/**
|
||||
* Allocate parameter.
|
||||
* Allocation parameter, which can be given when application calls
|
||||
* pj_turn_session_alloc() to allocate relay address in the TURN server.
|
||||
* Application should call pj_turn_alloc_param_default() to initialize
|
||||
* this structure with the default values.
|
||||
*/
|
||||
typedef struct pj_turn_alloc_param
|
||||
{
|
||||
/**
|
||||
* The requested BANDWIDTH. Default is zero to not request any
|
||||
* specific bandwidth.
|
||||
*/
|
||||
int bandwidth;
|
||||
|
||||
/**
|
||||
* The requested LIFETIME. Default is zero to not request any
|
||||
* explicit allocation lifetime.
|
||||
*/
|
||||
int lifetime;
|
||||
|
||||
/**
|
||||
* If set to non-zero, the TURN session will periodically send blank
|
||||
* Send Indication every PJ_TURN_KEEP_ALIVE_SEC to refresh local
|
||||
* NAT bindings. Default is zero.
|
||||
*/
|
||||
int ka_interval;
|
||||
|
||||
} pj_turn_alloc_param;
|
||||
|
||||
|
||||
/**
|
||||
* TURN session info.
|
||||
* This structure describes TURN session info.
|
||||
*/
|
||||
typedef struct pj_turn_session_info
|
||||
{
|
||||
|
@ -214,20 +267,30 @@ typedef struct pj_turn_session_info
|
|||
pj_turn_state_t state;
|
||||
|
||||
/**
|
||||
* Type of connection to the TURN server.
|
||||
* Last error (if session was terminated because of error)
|
||||
*/
|
||||
pj_turn_tp_type tp_type;
|
||||
pj_status_t last_status;
|
||||
|
||||
/**
|
||||
* The relay address
|
||||
* Type of connection to the TURN server.
|
||||
*/
|
||||
pj_sockaddr relay_addr;
|
||||
pj_turn_tp_type conn_type;
|
||||
|
||||
/**
|
||||
* The selected TURN server address.
|
||||
*/
|
||||
pj_sockaddr server;
|
||||
|
||||
/**
|
||||
* Mapped address, as reported by the TURN server.
|
||||
*/
|
||||
pj_sockaddr mapped_addr;
|
||||
|
||||
/**
|
||||
* The relay address
|
||||
*/
|
||||
pj_sockaddr relay_addr;
|
||||
|
||||
/**
|
||||
* Current seconds before allocation expires.
|
||||
*/
|
||||
|
@ -237,67 +300,173 @@ typedef struct pj_turn_session_info
|
|||
|
||||
|
||||
/**
|
||||
* Create default pj_turn_alloc_param.
|
||||
* Initialize pj_turn_alloc_param with the default values.
|
||||
*
|
||||
* @param prm The TURN allocation parameter to be initialized.
|
||||
*/
|
||||
PJ_DECL(void) pj_turn_alloc_param_default(pj_turn_alloc_param *prm);
|
||||
|
||||
|
||||
/**
|
||||
* Duplicate pj_turn_alloc_param.
|
||||
*
|
||||
* @param pool Pool to allocate memory (currently not used)
|
||||
* @param dst Destination parameter.
|
||||
* @param src Source parameter.
|
||||
*/
|
||||
PJ_DECL(void) pj_turn_alloc_param_copy(pj_pool_t *pool,
|
||||
pj_turn_alloc_param *dst,
|
||||
const pj_turn_alloc_param *src);
|
||||
|
||||
/**
|
||||
* Get TURN state name.
|
||||
* Get string representation for the given TURN state.
|
||||
*
|
||||
* @param state The TURN session state.
|
||||
*
|
||||
* @return The state name as NULL terminated string.
|
||||
*/
|
||||
PJ_DECL(const char*) pj_turn_state_name(pj_turn_state_t state);
|
||||
|
||||
|
||||
/**
|
||||
* Create TURN client session.
|
||||
* Create a TURN session instance with the specified address family and
|
||||
* connection type. Once TURN session instance is created, application
|
||||
* must call pj_turn_session_alloc() to allocate a relay address in the TURN
|
||||
* server.
|
||||
*
|
||||
* @param cfg The STUN configuration which contains among other
|
||||
* things the ioqueue and timer heap instance for
|
||||
* the operation of this session.
|
||||
* @param name Optional name to identify this session in the log.
|
||||
* @param af Address family of the client connection. Currently
|
||||
* pj_AF_INET() and pj_AF_INET6() are supported.
|
||||
* @param conn_type Connection type to the TURN server.
|
||||
* @param cb Callback to receive events from the TURN session.
|
||||
* @param options Option flags, currently this value must be zero.
|
||||
* @param user_data Arbitrary application data to be associated with
|
||||
* this transport.
|
||||
* @param p_sess Pointer to receive the created instance of the
|
||||
* TURN session.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successful,
|
||||
* or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_session_create(pj_stun_config *cfg,
|
||||
PJ_DECL(pj_status_t) pj_turn_session_create(const pj_stun_config *cfg,
|
||||
const char *name,
|
||||
int af,
|
||||
pj_turn_tp_type conn_type,
|
||||
const pj_turn_session_cb *cb,
|
||||
void *user_data,
|
||||
unsigned options,
|
||||
void *user_data,
|
||||
pj_turn_session **p_sess);
|
||||
|
||||
|
||||
/**
|
||||
* Shutdown TURN client session.
|
||||
* Shutdown TURN client session. This will gracefully deallocate and
|
||||
* destroy the client session.
|
||||
*
|
||||
* @param sess The TURN client session.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successful,
|
||||
* or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_session_shutdown(pj_turn_session *sess);
|
||||
|
||||
|
||||
/**
|
||||
* Forcefully destroy the TURN session.
|
||||
* Forcefully destroy the TURN session. This will destroy the session
|
||||
* immediately. If there is an active allocation, the server will not
|
||||
* be notified about the client destruction.
|
||||
*
|
||||
* @param sess The TURN client session.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successful,
|
||||
* or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_session_destroy(pj_turn_session *sess);
|
||||
|
||||
|
||||
/**
|
||||
* Get TURN session info.
|
||||
* Get the information about this TURN session and the allocation, if
|
||||
* any.
|
||||
*
|
||||
* @param sess The TURN client session.
|
||||
* @param info The structure to be initialized with the TURN
|
||||
* session info.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successful,
|
||||
* or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_session_get_info(pj_turn_session *sess,
|
||||
pj_turn_session_info *info);
|
||||
|
||||
/**
|
||||
* Re-assign user data.
|
||||
* Associate a user data with this TURN session. The user data may then
|
||||
* be retrieved later with pj_turn_session_get_user_data().
|
||||
*
|
||||
* @param sess The TURN client session.
|
||||
* @param user_data Arbitrary data.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successful,
|
||||
* or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_session_set_user_data(pj_turn_session *sess,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* Retrieve user data.
|
||||
* Retrieve the previously assigned user data associated with this TURN
|
||||
* session.
|
||||
*
|
||||
* @param sess The TURN client session.
|
||||
*
|
||||
* @return The user/application data.
|
||||
*/
|
||||
PJ_DECL(void*) pj_turn_session_get_user_data(pj_turn_session *sess);
|
||||
|
||||
|
||||
/**
|
||||
* Set the server or domain name of the server.
|
||||
* Configure message logging. By default all flags are enabled.
|
||||
*
|
||||
* @param sess The TURN client session.
|
||||
* @param flags Bitmask combination of #pj_stun_sess_msg_log_flag
|
||||
*/
|
||||
PJ_DECL(void) pj_turn_session_set_log(pj_turn_session *sess,
|
||||
unsigned flags);
|
||||
|
||||
|
||||
/**
|
||||
* Set the server or domain name of the server. Before the application
|
||||
* can send Allocate request (with pj_turn_session_alloc()), it must first
|
||||
* resolve the server address(es) using this function. This function will
|
||||
* resolve the TURN server using DNS SRV resolution if the \a resolver
|
||||
* is set. The server resolution process will complete asynchronously,
|
||||
* and application will be notified in \a on_state() callback with the
|
||||
* session state set to PJ_TURN_STATE_RESOLVED.
|
||||
*
|
||||
* Application may call with pj_turn_session_alloc() before the server
|
||||
* resolution completes. In this case, the operation will be queued by
|
||||
* the session, and it will be sent once the server resolution completes.
|
||||
*
|
||||
* @param sess The TURN client session.
|
||||
* @param domain The domain, hostname, or IP address of the TURN
|
||||
* server. When this parameter contains domain name,
|
||||
* the \a resolver parameter must be set to activate
|
||||
* DNS SRV resolution.
|
||||
* @param default_port The default TURN port number to use when DNS SRV
|
||||
* resolution is not used. If DNS SRV resolution is
|
||||
* used, the server port number will be set from the
|
||||
* DNS SRV records.
|
||||
* @param resolver If this parameter is not NULL, then the \a domain
|
||||
* parameter will be first resolved with DNS SRV and
|
||||
* then fallback to using DNS A/AAAA resolution when
|
||||
* DNS SRV resolution fails. If this parameter is
|
||||
* NULL, the \a domain parameter will be resolved as
|
||||
* hostname.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successfully
|
||||
* queued, or the appropriate error code on failure.
|
||||
* When this function returns PJ_SUCCESS, the final
|
||||
* result of the resolution process will be notified
|
||||
* to application in \a on_state() callback.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_session_set_server(pj_turn_session *sess,
|
||||
const pj_str_t *domain,
|
||||
|
@ -306,43 +475,120 @@ PJ_DECL(pj_status_t) pj_turn_session_set_server(pj_turn_session *sess,
|
|||
|
||||
|
||||
/**
|
||||
* Set credential to be used by the session.
|
||||
* Set credential to be used to authenticate against TURN server.
|
||||
* Application must call this function before sending Allocate request
|
||||
* with pj_turn_session_alloc().
|
||||
*
|
||||
* @param sess The TURN client session
|
||||
* @param cred STUN credential to be used.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successful,
|
||||
* or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_session_set_credential(pj_turn_session *sess,
|
||||
const pj_stun_auth_cred *cred);
|
||||
|
||||
|
||||
/**
|
||||
* Create TURN allocation.
|
||||
* Allocate a relay address/resource in the TURN server by sending TURN
|
||||
* Allocate request. Application must first initiate the server resolution
|
||||
* process with pj_turn_session_set_server() and set the credential to be
|
||||
* used with pj_turn_session_set_credential() before calling this function.
|
||||
*
|
||||
* This function will complete asynchronously, and the application will be
|
||||
* notified about the allocation result in \a on_state() callback. The
|
||||
* TURN session state will move to PJ_TURN_STATE_READY if allocation is
|
||||
* successful, and PJ_TURN_STATE_DEALLOCATING or greater state if allocation
|
||||
* has failed.
|
||||
*
|
||||
* Once allocation has been successful, the TURN session will keep this
|
||||
* allocation alive until the session is destroyed, by sending periodic
|
||||
* allocation refresh to the TURN server.
|
||||
*
|
||||
* @param sess The TURN client session.
|
||||
* @param param Optional TURN allocation parameter.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successfully
|
||||
* initiated or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_session_alloc(pj_turn_session *sess,
|
||||
const pj_turn_alloc_param *param);
|
||||
|
||||
|
||||
/**
|
||||
* Relay data to the specified peer through the session.
|
||||
* Send a data to the specified peer address via the TURN relay. This
|
||||
* function will encapsulate the data as STUN Send Indication or TURN
|
||||
* ChannelData packet and send the message to the TURN server. The TURN
|
||||
* server then will send the data to the peer.
|
||||
*
|
||||
* The allocation (pj_turn_session_alloc()) must have been successfully
|
||||
* created before application can relay any data.
|
||||
*
|
||||
* Since TURN session is transport independent, this function will
|
||||
* ultimately call \a on_send_pkt() callback to request the application
|
||||
* to actually send the packet containing the data to the TURN server.
|
||||
*
|
||||
* @param sess The TURN client session.
|
||||
* @param pkt The data/packet to be sent to peer.
|
||||
* @param pkt_len Length of the data.
|
||||
* @param peer_addr The remote peer address (the ultimate destination
|
||||
* of the data, and not the TURN server address).
|
||||
* @param addr_len Length of the address.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successful,
|
||||
* or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_session_sendto(pj_turn_session *sess,
|
||||
const pj_uint8_t *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *addr,
|
||||
const pj_sockaddr_t *peer_addr,
|
||||
unsigned addr_len);
|
||||
|
||||
/**
|
||||
* Bind a peer address to a channel number.
|
||||
* Optionally establish channel binding for the specified a peer address.
|
||||
* This function will assign a unique channel number for the peer address
|
||||
* and request channel binding to the TURN server for this address. When
|
||||
* a channel has been bound to a peer, the TURN client and TURN server
|
||||
* will exchange data using ChannelData encapsulation format, which has
|
||||
* lower bandwidth overhead than Send Indication (the default format used
|
||||
* when peer address is not bound to a channel).
|
||||
*
|
||||
* This function will complete asynchronously, and application will be
|
||||
* notified about the result in \a on_channel_bound() callback.
|
||||
*
|
||||
* @param sess The TURN client session.
|
||||
* @param peer The remote peer address.
|
||||
* @param addr_len Length of the address.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successfully
|
||||
* initiated, or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_session_bind_channel(pj_turn_session *sess,
|
||||
const pj_sockaddr_t *peer,
|
||||
unsigned addr_len);
|
||||
|
||||
/**
|
||||
* Notify TURN client session upon receiving a packet from server.
|
||||
* The packet maybe a STUN packet or ChannelData packet.
|
||||
* Notify TURN client session upon receiving a packet from server. Since
|
||||
* the TURN session is transport independent, it does not read packet from
|
||||
* any sockets, and rather relies on application giving it packets that
|
||||
* are received from the TURN server. The session then processes this packet
|
||||
* and decides whether it is part of TURN protocol exchange or if it is a
|
||||
* data to be reported back to user, which in this case it will call the
|
||||
* \a on_rx_data() callback.
|
||||
*
|
||||
* @param sess The TURN client session.
|
||||
* @param pkt The packet as received from the TURN server. This
|
||||
* should contain either STUN encapsulated message or
|
||||
* a ChannelData packet.
|
||||
* @param pkt_len The length of the packet.
|
||||
*
|
||||
* @return The function may return non-PJ_SUCCESS if it receives
|
||||
* non-STUN and non-ChannelData packet, or if the
|
||||
* \a on_rx_data() returns non-PJ_SUCCESS;
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess,
|
||||
const pj_uint8_t *pkt,
|
||||
unsigned pkt_len,
|
||||
pj_bool_t is_datagram);
|
||||
void *pkt,
|
||||
unsigned pkt_len);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef __PJNATH_turn_sock_H__
|
||||
#define __PJNATH_turn_sock_H__
|
||||
#ifndef __PJNATH_TURN_SOCK_H__
|
||||
#define __PJNATH_TURN_SOCK_H__
|
||||
|
||||
/**
|
||||
* @file turn_sock.h
|
||||
|
@ -31,46 +31,87 @@ PJ_BEGIN_DECL
|
|||
|
||||
/* **************************************************************************/
|
||||
/**
|
||||
* @defgroup PJNATH_TURN_UDP TURN TCP client
|
||||
* @brief TURN relay using TCP client as transport protocol
|
||||
* @ingroup PJNATH_STUN
|
||||
* @defgroup PJNATH_TURN_SOCK TURN client transport
|
||||
* @brief Client transport utilizing TURN relay
|
||||
* @ingroup PJNATH_TURN
|
||||
* @{
|
||||
*
|
||||
* The TURN relay client transport can be used to relay data from the client
|
||||
* to peer via a TURN relay. The application establishes TURN connection to
|
||||
* the TURN server using UDP or TCP as the transport, then creates a relay
|
||||
* address in the TURN server to be advertised to remote peer(s) as the
|
||||
* transport address. When application sends data to a remote address via
|
||||
* this transport, the data will be sent via the TURN relay, and vice versa.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Opaque declaration for TURN TCP client.
|
||||
* Opaque declaration for TURN client.
|
||||
*/
|
||||
typedef struct pj_turn_sock pj_turn_sock;
|
||||
|
||||
|
||||
/**
|
||||
* This structure contains callbacks that will be called by the TURN
|
||||
* transport.
|
||||
*/
|
||||
typedef struct pj_turn_sock_cb
|
||||
{
|
||||
/**
|
||||
* Notification when incoming data has been received, either through
|
||||
* Data indication or ChannelData message from the TURN server.
|
||||
* Notification when incoming data has been received from the remote
|
||||
* peer via the TURN server. The data reported in this callback will
|
||||
* be the exact data as sent by the peer (e.g. the TURN encapsulation
|
||||
* such as Data Indication or ChannelData will be removed before this
|
||||
* function is called).
|
||||
*
|
||||
* This callback is mandatory.
|
||||
* @param turn_sock The TURN client transport.
|
||||
* @param data The data as received from the peer.
|
||||
* @param data_len Length of the data.
|
||||
* @param peer_addr The peer address.
|
||||
* @param addr_len The length of the peer address.
|
||||
*/
|
||||
void (*on_rx_data)(pj_turn_sock *turn_sock,
|
||||
const pj_uint8_t *pkt,
|
||||
void *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *peer_addr,
|
||||
unsigned addr_len);
|
||||
|
||||
/**
|
||||
* Notification when TURN session state has changed. Application should
|
||||
* implement this callback to know that the TURN session is no longer
|
||||
* available.
|
||||
* implement this callback to monitor the progress of the TURN session.
|
||||
*
|
||||
* @param turn_sock The TURN client transport.
|
||||
* @param old_state Previous state.
|
||||
* @param new_state Current state.
|
||||
*/
|
||||
void (*on_state)(pj_turn_sock *turn_sock, pj_turn_state_t old_state,
|
||||
void (*on_state)(pj_turn_sock *turn_sock,
|
||||
pj_turn_state_t old_state,
|
||||
pj_turn_state_t new_state);
|
||||
|
||||
} pj_turn_sock_cb;
|
||||
|
||||
|
||||
/**
|
||||
* Create.
|
||||
* Create a TURN transport instance with the specified address family and
|
||||
* connection type. Once TURN transport instance is created, application
|
||||
* must call pj_turn_sock_alloc() to allocate a relay address in the TURN
|
||||
* server.
|
||||
*
|
||||
* @param cfg The STUN configuration which contains among other
|
||||
* things the ioqueue and timer heap instance for
|
||||
* the operation of this transport.
|
||||
* @param af Address family of the client connection. Currently
|
||||
* pj_AF_INET() and pj_AF_INET6() are supported.
|
||||
* @param conn_type Connection type to the TURN server. Both TCP and
|
||||
* UDP are supported.
|
||||
* @param cb Callback to receive events from the TURN transport.
|
||||
* @param options Option flags, currently this value must be zero.
|
||||
* @param user_data Arbitrary application data to be associated with
|
||||
* this transport.
|
||||
* @param p_turn_sock Pointer to receive the created instance of the
|
||||
* TURN transport.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successful,
|
||||
* or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_sock_create(pj_stun_config *cfg,
|
||||
int af,
|
||||
|
@ -81,53 +122,174 @@ PJ_DECL(pj_status_t) pj_turn_sock_create(pj_stun_config *cfg,
|
|||
pj_turn_sock **p_turn_sock);
|
||||
|
||||
/**
|
||||
* Destroy.
|
||||
* Destroy the TURN transport instance. This will gracefully close the
|
||||
* connection between the client and the TURN server. Although this
|
||||
* function will return immediately, the TURN socket deletion may continue
|
||||
* in the background and the application may still get state changes
|
||||
* notifications from this transport.
|
||||
*
|
||||
* @param turn_sock The TURN transport instance.
|
||||
*/
|
||||
PJ_DECL(void) pj_turn_sock_destroy(pj_turn_sock *turn_sock);
|
||||
|
||||
/**
|
||||
* Set user data.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_sock_set_user_data(pj_turn_sock *turn_sock,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* Get user data.
|
||||
* Associate a user data with this TURN transport. The user data may then
|
||||
* be retrieved later with #pj_turn_sock_get_user_data().
|
||||
*
|
||||
* @param turn_sock The TURN transport instance.
|
||||
* @param user_data Arbitrary data.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successful,
|
||||
* or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_sock_set_user_data(pj_turn_sock *turn_sock,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* Retrieve the previously assigned user data associated with this TURN
|
||||
* transport.
|
||||
*
|
||||
* @param turn_sock The TURN transport instance.
|
||||
*
|
||||
* @return The user/application data.
|
||||
*/
|
||||
PJ_DECL(void*) pj_turn_sock_get_user_data(pj_turn_sock *turn_sock);
|
||||
|
||||
|
||||
/**
|
||||
* Get info.
|
||||
* Get the TURN transport info. The transport info contains, among other
|
||||
* things, the allocated relay address.
|
||||
*
|
||||
* @param turn_sock The TURN transport instance.
|
||||
* @param info Pointer to be filled with TURN transport info.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successful,
|
||||
* or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_sock_get_info(pj_turn_sock *turn_sock,
|
||||
pj_turn_session_info *info);
|
||||
pj_turn_session_info *info);
|
||||
|
||||
/**
|
||||
* Initialize.
|
||||
* Acquire the internal mutex of the TURN transport. Application may need
|
||||
* to call this function to synchronize access to other objects alongside
|
||||
* the TURN transport, to avoid deadlock.
|
||||
*
|
||||
* @param turn_sock The TURN transport instance.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successful,
|
||||
* or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_sock_init(pj_turn_sock *turn_sock,
|
||||
const pj_str_t *domain,
|
||||
int default_port,
|
||||
pj_dns_resolver *resolver,
|
||||
const pj_stun_auth_cred *cred,
|
||||
const pj_turn_alloc_param *param);
|
||||
PJ_DECL(pj_status_t) pj_turn_sock_lock(pj_turn_sock *turn_sock);
|
||||
|
||||
|
||||
/**
|
||||
* Send packet.
|
||||
* Release the internal mutex previously held with pj_turn_sock_lock().
|
||||
*
|
||||
* @param turn_sock The TURN transport instance.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successful,
|
||||
* or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_sock_unlock(pj_turn_sock *turn_sock);
|
||||
|
||||
|
||||
/**
|
||||
* Set STUN message logging for this TURN session.
|
||||
* See #pj_stun_session_set_log().
|
||||
*
|
||||
* @param turn_sock The TURN transport instance.
|
||||
* @param flags Bitmask combination of #pj_stun_sess_msg_log_flag
|
||||
*/
|
||||
PJ_DECL(void) pj_turn_sock_set_log(pj_turn_sock *turn_sock,
|
||||
unsigned flags);
|
||||
|
||||
/**
|
||||
* Allocate a relay address/resource in the TURN server. This function
|
||||
* will resolve the TURN server using DNS SRV (if desired) and send TURN
|
||||
* \a Allocate request using the specified credential to allocate a relay
|
||||
* address in the server. This function completes asynchronously, and
|
||||
* application will be notified when the allocation process has been
|
||||
* successful in the \a on_state() callback when the state is set to
|
||||
* PJ_TURN_STATE_READY. If the allocation fails, the state will be set
|
||||
* to PJ_TURN_STATE_DEALLOCATING or greater.
|
||||
*
|
||||
* @param turn_sock The TURN transport instance.
|
||||
* @param domain The domain, hostname, or IP address of the TURN
|
||||
* server. When this parameter contains domain name,
|
||||
* the \a resolver parameter must be set to activate
|
||||
* DNS SRV resolution.
|
||||
* @param default_port The default TURN port number to use when DNS SRV
|
||||
* resolution is not used. If DNS SRV resolution is
|
||||
* used, the server port number will be set from the
|
||||
* DNS SRV records.
|
||||
* @param resolver If this parameter is not NULL, then the \a domain
|
||||
* parameter will be first resolved with DNS SRV and
|
||||
* then fallback to using DNS A/AAAA resolution when
|
||||
* DNS SRV resolution fails. If this parameter is
|
||||
* NULL, the \a domain parameter will be resolved as
|
||||
* hostname.
|
||||
* @param cred The STUN credential to be used for the TURN server.
|
||||
* @param param Optional TURN allocation parameter.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successfully
|
||||
* queued, or the appropriate error code on failure.
|
||||
* When this function returns PJ_SUCCESS, the final
|
||||
* result of the allocation process will be notified
|
||||
* to application in \a on_state() callback.
|
||||
*
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_sock_alloc(pj_turn_sock *turn_sock,
|
||||
const pj_str_t *domain,
|
||||
int default_port,
|
||||
pj_dns_resolver *resolver,
|
||||
const pj_stun_auth_cred *cred,
|
||||
const pj_turn_alloc_param *param);
|
||||
|
||||
/**
|
||||
* Send a data to the specified peer address via the TURN relay. This
|
||||
* function will encapsulate the data as STUN Send Indication or TURN
|
||||
* ChannelData packet and send the message to the TURN server. The TURN
|
||||
* server then will send the data to the peer.
|
||||
*
|
||||
* The allocation (pj_turn_sock_alloc()) must have been successfully
|
||||
* created before application can relay any data.
|
||||
*
|
||||
* @param turn_sock The TURN transport instance.
|
||||
* @param pkt The data/packet to be sent to peer.
|
||||
* @param pkt_len Length of the data.
|
||||
* @param peer_addr The remote peer address (the ultimate destination
|
||||
* of the data, and not the TURN server address).
|
||||
* @param addr_len Length of the address.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successful,
|
||||
* or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_sock_sendto(pj_turn_sock *turn_sock,
|
||||
const pj_uint8_t *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *addr,
|
||||
const pj_sockaddr_t *peer_addr,
|
||||
unsigned addr_len);
|
||||
|
||||
/**
|
||||
* Bind a peer address to a channel number.
|
||||
* Optionally establish channel binding for the specified a peer address.
|
||||
* This function will assign a unique channel number for the peer address
|
||||
* and request channel binding to the TURN server for this address. When
|
||||
* a channel has been bound to a peer, the TURN transport and TURN server
|
||||
* will exchange data using ChannelData encapsulation format, which has
|
||||
* lower bandwidth overhead than Send Indication (the default format used
|
||||
* when peer address is not bound to a channel).
|
||||
*
|
||||
* @param turn_sock The TURN transport instance.
|
||||
* @param peer The remote peer address.
|
||||
* @param addr_len Length of the address.
|
||||
*
|
||||
* @return PJ_SUCCESS if the operation has been successful,
|
||||
* or the appropriate error code on failure.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_sock_bind_channel(pj_turn_sock *turn_sock,
|
||||
const pj_sockaddr_t *peer,
|
||||
unsigned addr_len);
|
||||
const pj_sockaddr_t *peer,
|
||||
unsigned addr_len);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -138,5 +300,5 @@ PJ_DECL(pj_status_t) pj_turn_sock_bind_channel(pj_turn_sock *turn_sock,
|
|||
PJ_END_DECL
|
||||
|
||||
|
||||
#endif /* __PJNATH_turn_sock_H__ */
|
||||
#endif /* __PJNATH_TURN_SOCK_H__ */
|
||||
|
||||
|
|
|
@ -34,6 +34,13 @@
|
|||
|
||||
PJ_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* This constant describes a number to be used to identify an invalid TURN
|
||||
* channel number.
|
||||
*/
|
||||
#define PJ_TURN_INVALID_CHANNEL 0xFFFF
|
||||
|
||||
|
||||
/**
|
||||
* Initialize pjnath library.
|
||||
*
|
||||
|
@ -43,7 +50,7 @@ PJ_DECL(pj_status_t) pjnath_init(void);
|
|||
|
||||
|
||||
/**
|
||||
* Display error to the log.
|
||||
* Display error to the log.
|
||||
*
|
||||
* @param sender The sender name.
|
||||
* @param title Title message.
|
||||
|
@ -67,167 +74,216 @@ PJ_END_DECL
|
|||
/* Doxygen documentation below: */
|
||||
|
||||
/**
|
||||
* @mainpage PJNATH - Open Source ICE, STUN, and TURN Library
|
||||
*
|
||||
* \n
|
||||
* This is the documentation of PJNATH, an Open Source library providing
|
||||
* NAT traversal helper functionalities by using standard based protocols.
|
||||
*
|
||||
* \n
|
||||
|
||||
* \section PJNATH_STUN STUN Protocol Library
|
||||
*
|
||||
* Session Traversal Utilities (STUN, or previously known as Simple
|
||||
* Traversal of User Datagram Protocol (UDP) Through Network Address
|
||||
* Translators (NAT)s), is a lightweight protocol that serves as a tool for
|
||||
* application protocols in dealing with NAT traversal. It allows a client
|
||||
* to determine the IP address and port allocated to them by a NAT and to
|
||||
* keep NAT bindings open.
|
||||
*
|
||||
* The PJNATH library provides facilities to support both the core
|
||||
* <B>STUN-bis</B> specification and the <B>TURN</B> usage of STUN,
|
||||
* as well as other STUN usages. Please see #pj_stun_attr_type for
|
||||
* list of STUN attributes supported by this library.
|
||||
*
|
||||
*
|
||||
* The following are some design principles that have been utilized
|
||||
* when implementing the STUN library in PJNATH:
|
||||
*
|
||||
* - layered architecture, with \ref PJNATH_STUN_MSG as the lowest
|
||||
* layer and \ref PJNATH_STUN_SESSION as the highest abstraction
|
||||
* layer, to accommodate various usage scenario of the library.
|
||||
*
|
||||
* - no transport -- the STUN library is pretty much transport
|
||||
* independent and all sending and receiving functionalities will
|
||||
* have to be implemented by application or higher level
|
||||
* abstraction (such as ICE). This helps facilitating an even
|
||||
* more usage scenarios of the library.
|
||||
*
|
||||
* - common functionalities for both STUN client and server
|
||||
* development. All STUN components can be used to develop both
|
||||
* STUN client and STUN server application, and in fact, in ICE,
|
||||
* both STUN client and server functionality exist in a single
|
||||
* ICE session.
|
||||
*
|
||||
* \n
|
||||
*
|
||||
* \subsection PJNATH_STUN_ARCH STUN Library Organization
|
||||
*
|
||||
* \image html stun-arch.jpg "STUN Library Architecture"
|
||||
*
|
||||
* The STUN library is organized as follows:
|
||||
*
|
||||
* - for both client and server, the highest abstraction is
|
||||
* \ref PJNATH_STUN_SESSION, which provides management of incoming
|
||||
* and outgoing messages and association of STUN credential to
|
||||
* a STUN session.
|
||||
*
|
||||
* - for client, the next layer below is \ref PJNATH_STUN_TRANSACTION,
|
||||
* which manages retransmissions of STUN request. Server side STUN
|
||||
* transaction is handled in \ref PJNATH_STUN_SESSION layer above.
|
||||
*
|
||||
* - \ref PJNATH_STUN_AUTH provides mechanism to verify STUN
|
||||
* credential in incoming STUN messages.
|
||||
*
|
||||
* - the lowest layer of the library is \ref PJNATH_STUN_MSG. This layer
|
||||
* provides STUN message representation, validation, parsing,
|
||||
* encoding MESSAGE-INTEGRITY for outgoing messages, and
|
||||
* debugging (dump to log) of STUN messages.
|
||||
*
|
||||
* All STUN library components are independent of any transports.
|
||||
* Application gives incoming packet to the STUN components for processing,
|
||||
* and it must supply the STUN components with callback to send outgoing
|
||||
* messages.
|
||||
*
|
||||
*
|
||||
* \n
|
||||
*
|
||||
* \subsection PJNATH_STUN_CLASSES PJNATH Class Diagram
|
||||
*
|
||||
*
|
||||
* \image html UML-class-diagram.png "Class Diagram"
|
||||
*
|
||||
* TBD: write descriptions.
|
||||
*
|
||||
* \subsection PJNATH_STUN_USING Using STUN Library
|
||||
*
|
||||
* [The developers guide documentation can certainly be improved here]
|
||||
*
|
||||
* For a sample STUN and TURN client, please see <tt>pjstun-client</tt>
|
||||
* project under <tt>pjnath/src</tt> directory.
|
||||
*
|
||||
* For a sample STUN and TURN server, please see <tt>pjstun-srv-test</tt>
|
||||
* project under <tt>pjnath/src</tt> directory.
|
||||
*
|
||||
*
|
||||
* \subsection PJNATH_STUN_REF STUN Reference
|
||||
*
|
||||
* References for STUN:
|
||||
*
|
||||
* - <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-behave-rfc3489bis-15.txt">
|
||||
* <B>draft-ietf-behave-rfc3489bis-15</b></A>: Session Traversal
|
||||
* Utilities for (NAT) (STUN),
|
||||
* - <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-behave-turn-07.txt">
|
||||
* <B>draft-ietf-behave-turn-07</B></A>: Obtaining Relay Addresses
|
||||
* from Simple Traversal Underneath NAT (STUN)
|
||||
* - Obsoleted: <A HREF="http://www.ietf.org/rfc/rfc3489.txt">RFC 3489</A>.
|
||||
*
|
||||
* \n
|
||||
*
|
||||
* \section PJNATH_ICE ICE Implementation
|
||||
*
|
||||
* Interactive Connectivity Establishment (ICE) is a standard based
|
||||
* methodology for traversing Network Address Translator (NAT), and
|
||||
* is described in
|
||||
* <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-mmusic-ice-19.txt">
|
||||
* <B>draft-ietf-mmusic-ice-19.txt</B></A> draft. The PJNATH ICE
|
||||
* implementation is aimed to provide a usable and generic ICE transports
|
||||
* for different types of application, including but not limited to
|
||||
* the usage of ICE in SIP/SDP offer/answer.
|
||||
*
|
||||
*
|
||||
* \subsection PJNATH_ICE_ARCH ICE Library Organization
|
||||
*
|
||||
* \image html ice-arch.jpg "ICE Architecture"
|
||||
*
|
||||
* The ICE library is organized as follows:
|
||||
*
|
||||
* - the highest abstraction is ICE media transport, which maintains
|
||||
* ICE stream transport and provides SDP translations to be used
|
||||
* for SIP offer/answer exchanges. ICE media transport is part
|
||||
* of PJMEDIA library.
|
||||
*
|
||||
* - higher in the hierarchy is \ref PJNATH_ICE_STREAM_TRANSPORT,
|
||||
* which binds ICE with UDP sockets, and provides STUN binding
|
||||
* and relay/TURN allocation for the sockets. This component can
|
||||
* be directly used by application, although normally application
|
||||
* should use the next higher abstraction since it provides
|
||||
* SDP translations and better integration with other PJ libraries
|
||||
* such as PJSIP and PJMEDIA.
|
||||
*
|
||||
* - the lowest layer is \ref PJNATH_ICE_SESSION, which provides
|
||||
* ICE management and negotiation in a transport-independent way.
|
||||
* This layer contains the state machines to perform ICE
|
||||
* negotiation, and provides the most flexibility to control all
|
||||
* aspects of ICE session. This layer normally is only usable for
|
||||
* ICE implementors.
|
||||
*
|
||||
* \subsection PJNATH_ICE_USING Using the ICE Library
|
||||
*
|
||||
* For ICE implementation that has been integrated with socket transport,
|
||||
* please see \ref PJNATH_ICE_STREAM_TRANSPORT_USING.
|
||||
*
|
||||
* For ICE implementation that has not been integrated with socket
|
||||
* transport, please see \ref pj_ice_sess_using_sec.
|
||||
*
|
||||
* \subsection PJNATH_ICE_REF Reference
|
||||
*
|
||||
* References for ICE:
|
||||
* - <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-mmusic-ice-19.txt">
|
||||
* <B>draft-ietf-mmusic-ice-19.txt</B></A>: Interactive Connectivity
|
||||
* Establishment (ICE): A Methodology for Network Address Translator
|
||||
* (NAT) Traversal for Offer/Answer Protocols
|
||||
*/
|
||||
@mainpage PJNATH - Open Source ICE, STUN, and TURN Library
|
||||
|
||||
\n
|
||||
This is the documentation of PJNATH, an Open Source library providing
|
||||
NAT traversal helper functionalities by using standard based protocols
|
||||
such as STUN, TURN, and ICE.
|
||||
|
||||
\n
|
||||
\n
|
||||
|
||||
\section lib_comps Library Components
|
||||
|
||||
\subsection comp_stun STUN
|
||||
|
||||
Session Traversal Utilities (STUN, or previously known as Simple
|
||||
Traversal of User Datagram Protocol (UDP) Through Network Address
|
||||
Translators (NAT)s), is a lightweight protocol that serves as a tool for
|
||||
application protocols in dealing with NAT traversal. It allows a client
|
||||
to determine the IP address and port allocated to them by a NAT and to
|
||||
keep NAT bindings open.
|
||||
|
||||
This version of PJNATH implements the following STUN-bis draft:
|
||||
- <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-behave-rfc3489bis-15.txt">
|
||||
<B>draft-ietf-behave-rfc3489bis-15</b></A>: Session Traversal
|
||||
Utilities for (NAT) (STUN),
|
||||
|
||||
|
||||
\subsection comp_turn TURN
|
||||
|
||||
Traversal Using Relays around NAT (TURN) allows the host to control the
|
||||
operation of the relay and to exchange packets with its peers using the relay.
|
||||
|
||||
This version of PJNATH implements both TCP and UDP client transport and it
|
||||
complies with the following TURN draft:
|
||||
- <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-behave-turn-07.txt">
|
||||
<B>draft-ietf-behave-turn-07</B></A>: Obtaining Relay Addresses
|
||||
from Simple Traversal Underneath NAT (STUN)
|
||||
|
||||
|
||||
\subsection comp_ice ICE
|
||||
|
||||
Interactive Connectivity Establishment (ICE) is a standard based
|
||||
methodology for traversing Network Address Translator (NAT). This
|
||||
implementation is aimed to provide a usable and generic ICE transports
|
||||
for different types of application, including but not limited to
|
||||
the usage of ICE in SIP/SDP offer/answer.
|
||||
|
||||
|
||||
This version of PJNATH implements the following ICE draft:
|
||||
- <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-mmusic-ice-19.txt">
|
||||
<B>draft-ietf-mmusic-ice-19.txt</B></A> draft. The PJNATH ICE
|
||||
|
||||
|
||||
\subsection comp_natck NAT Classification Utility
|
||||
|
||||
The PJNATH library also provides NAT classification utility as
|
||||
described in <A HREF="http://www.ietf.org/rfc/rfc3489.txt">RFC 3489</A>.
|
||||
While the practice to detect the NAT type to assist NAT traversal
|
||||
has been deprecated in favor of ICE, the information may still be
|
||||
useful for troubleshooting purposes, hence the utility is provided.
|
||||
|
||||
|
||||
\n
|
||||
\n
|
||||
|
||||
\section lib_org Library Organization
|
||||
|
||||
The PJNATH library consists of many components with each providing
|
||||
specific functionality that may or may not be of the interests of
|
||||
applications (or application developers). This section attempts to
|
||||
give brief overview on the components provided by PJNATH.
|
||||
|
||||
The PJNATH components from the highest layer to the lower layer are
|
||||
as follows.
|
||||
|
||||
|
||||
\n
|
||||
|
||||
\subsection user_comp High-level Transport Objects
|
||||
|
||||
PJNATH library provides some high-level objects that may be used
|
||||
by applications:
|
||||
|
||||
|
||||
\subsubsection stun_sock STUN Transport
|
||||
|
||||
The \ref PJNATH_STUN_SOCK provides asynchronous UDP like socket transport
|
||||
with the additional capability to query the publicly mapped transport
|
||||
address (using STUN resolution), to refresh the NAT binding, and to
|
||||
demultiplex internal STUN messages from application data (the
|
||||
application data may be a STUN message as well).
|
||||
|
||||
|
||||
\subsubsection turn_sock TURN Client Transport
|
||||
|
||||
The \ref PJNATH_TURN_SOCK may be used by the application to send and
|
||||
receive data via TURN server. For more information please see the
|
||||
documentation of \ref PJNATH_TURN_SOCK.
|
||||
|
||||
|
||||
\subsubsection ice_strans ICE Stream Transport
|
||||
|
||||
The \ref PJNATH_ICE_STREAM_TRANSPORT provides transport interface to
|
||||
send and receive data through connection that is negotiated
|
||||
with ICE protocol. The \ref PJNATH_ICE_STREAM_TRANSPORT naturally
|
||||
contains both STUN Transport and \ref PJNATH_TURN_SOCK.
|
||||
|
||||
The \ref PJNATH_ICE_STREAM_TRANSPORT interface is suitable for both
|
||||
SIP or non-SIP use. For SIP use, application may prefer to use the
|
||||
ICE media transport in PJMEDIA instead where it has been integrated
|
||||
with the SDP offer and answer mechanism.
|
||||
|
||||
|
||||
\subsubsection natck NAT Classification Utility
|
||||
|
||||
PJNATH also provides \a PJNATH_NAT_DETECT to assist troubleshooting
|
||||
of problems related to NAT traversal.
|
||||
|
||||
|
||||
|
||||
\n
|
||||
|
||||
|
||||
\subsection sessions Transport Independent Sessions Layer
|
||||
|
||||
Right below the high level transports objects are the transport
|
||||
independent sessions. These sessions don't have access to sockets,
|
||||
so higher level objects (such as transports) must give incoming
|
||||
packets to the sessions and provide callback to be called by
|
||||
sessions to send outgoing packets.
|
||||
|
||||
|
||||
\subsubsection ice_sess ICE Session
|
||||
|
||||
The \ref PJNATH_ICE_SESSION is used by the \ref PJNATH_ICE_STREAM_TRANSPORT
|
||||
and contains the actual logic of the ICE negotiation.
|
||||
|
||||
|
||||
\subsubsection turn_sess TURN Session
|
||||
|
||||
The \ref PJNATH_TURN_SESSION is used by the \ref PJNATH_TURN_SOCK
|
||||
and it contains TURN protocol logic. Implementors may implement
|
||||
other types of TURN client connection (such as TURN TLS client)
|
||||
by utilizing this session.
|
||||
|
||||
|
||||
\subsubsection stun_sess STUN Session
|
||||
|
||||
The \ref PJNATH_STUN_SESSION manages STUN message exchange between
|
||||
a client and server (or vice versa). It manages \ref PJNATH_STUN_TRANSACTION
|
||||
for sending or receiving requests and \ref PJNATH_STUN_AUTH for both
|
||||
both incoming and outgoing STUN messages.
|
||||
|
||||
The \ref PJNATH_STUN_SESSION is naturally used by the \ref PJNATH_TURN_SESSION
|
||||
and \ref PJNATH_ICE_SESSION
|
||||
|
||||
|
||||
\n
|
||||
|
||||
\subsection stun_tsx STUN Transaction Layer
|
||||
|
||||
The \ref PJNATH_STUN_TRANSACTION is a thin layer to manage retransmission
|
||||
of STUN requests.
|
||||
|
||||
|
||||
\n
|
||||
|
||||
|
||||
\subsection stun_msg STUN Messaging Layer
|
||||
|
||||
At the very bottom of the PJNATH components is the \ref PJNATH_STUN_MSG
|
||||
layer. The API contains various representation of STUN messaging components
|
||||
and it provides API to encode and decode STUN messages.
|
||||
|
||||
|
||||
|
||||
\n
|
||||
\n
|
||||
|
||||
\section class_dia Class Diagram
|
||||
|
||||
|
||||
The following class diagram shows the interactions between objects in
|
||||
PJNATH:
|
||||
|
||||
\image html UML-class-diagram.png "Class Diagram"
|
||||
\image latex UML-class-diagram.png "Class Diagram"
|
||||
|
||||
|
||||
|
||||
\n
|
||||
\n
|
||||
|
||||
\section samples Sample Applications
|
||||
|
||||
|
||||
Some sample applications have been provided with PJNATH, and it's available
|
||||
under <tt>pjnath/src</tt> directory:
|
||||
|
||||
- <b>pjturn-client</b>: this is a stand-alone, console based TURN client
|
||||
application to be used as a demonstration for PJNATH TURN client
|
||||
transport API and for simple testing against TURN server implementations.
|
||||
The client supports both UDP and TCP connection to the TURN server.
|
||||
|
||||
- <b>pjturn-srv</b>: this is a simple TURN server to be used for testing
|
||||
purposes. It supports both UDP and TCP connections to the clients.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup PJNATH_STUN STUN Library
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,652 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
* Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "server.h"
|
||||
#include "test.h"
|
||||
|
||||
#define THIS_FILE "server.c"
|
||||
#define MAX_STUN_PKT 1500
|
||||
#define TURN_NONCE "thenonce"
|
||||
|
||||
static pj_bool_t stun_on_data_recvfrom(pj_activesock_t *asock,
|
||||
void *data,
|
||||
pj_size_t size,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
int addr_len,
|
||||
pj_status_t status);
|
||||
static pj_bool_t turn_on_data_recvfrom(pj_activesock_t *asock,
|
||||
void *data,
|
||||
pj_size_t size,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
int addr_len,
|
||||
pj_status_t status);
|
||||
static pj_bool_t alloc_on_data_recvfrom(pj_activesock_t *asock,
|
||||
void *data,
|
||||
pj_size_t size,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
int addr_len,
|
||||
pj_status_t status);
|
||||
|
||||
pj_status_t create_test_server(pj_stun_config *stun_cfg,
|
||||
pj_uint32_t flags,
|
||||
const char *domain,
|
||||
test_server **p_test_srv)
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
test_server *test_srv;
|
||||
pj_sockaddr hostip;
|
||||
char strbuf[100];
|
||||
pj_status_t status;
|
||||
|
||||
PJ_ASSERT_RETURN(stun_cfg && domain && p_test_srv, PJ_EINVAL);
|
||||
|
||||
status = pj_gethostip(pj_AF_INET(), &hostip);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
pool = pj_pool_create(mem, THIS_FILE, 512, 512, NULL);
|
||||
test_srv = (test_server*) PJ_POOL_ZALLOC_T(pool, test_server);
|
||||
test_srv->pool = pool;
|
||||
test_srv->flags = flags;
|
||||
test_srv->stun_cfg = stun_cfg;
|
||||
|
||||
pj_strdup2(pool, &test_srv->domain, domain);
|
||||
test_srv->username = pj_str(TURN_USERNAME);
|
||||
test_srv->passwd = pj_str(TURN_PASSWD);
|
||||
|
||||
pj_ioqueue_op_key_init(&test_srv->send_key, sizeof(test_srv->send_key));
|
||||
|
||||
if (flags & CREATE_DNS_SERVER) {
|
||||
status = pj_dns_server_create(mem, test_srv->stun_cfg->ioqueue,
|
||||
pj_AF_INET(), DNS_SERVER_PORT,
|
||||
0, &test_srv->dns_server);
|
||||
if (status != PJ_SUCCESS) {
|
||||
destroy_test_server(test_srv);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Add DNS A record for the domain, for fallback */
|
||||
if (flags & CREATE_A_RECORD_FOR_DOMAIN) {
|
||||
pj_dns_parsed_rr rr;
|
||||
pj_str_t res_name;
|
||||
pj_in_addr ip_addr;
|
||||
|
||||
pj_strdup2(pool, &res_name, domain);
|
||||
ip_addr = hostip.ipv4.sin_addr;
|
||||
pj_dns_init_a_rr(&rr, &res_name, PJ_DNS_CLASS_IN, 60, &ip_addr);
|
||||
pj_dns_server_add_rec(test_srv->dns_server, 1, &rr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (flags & CREATE_STUN_SERVER) {
|
||||
pj_activesock_cb stun_sock_cb;
|
||||
pj_sockaddr bound_addr;
|
||||
|
||||
pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb));
|
||||
stun_sock_cb.on_data_recvfrom = &stun_on_data_recvfrom;
|
||||
|
||||
pj_sockaddr_in_init(&bound_addr.ipv4, NULL, STUN_SERVER_PORT);
|
||||
|
||||
status = pj_activesock_create_udp(pool, &bound_addr, NULL,
|
||||
test_srv->stun_cfg->ioqueue,
|
||||
&stun_sock_cb, test_srv,
|
||||
&test_srv->stun_sock, NULL);
|
||||
if (status != PJ_SUCCESS) {
|
||||
destroy_test_server(test_srv);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = pj_activesock_start_recvfrom(test_srv->stun_sock, pool,
|
||||
MAX_STUN_PKT, 0);
|
||||
if (status != PJ_SUCCESS) {
|
||||
destroy_test_server(test_srv);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (test_srv->dns_server && (flags & CREATE_STUN_SERVER_DNS_SRV)) {
|
||||
pj_str_t res_name, target;
|
||||
pj_dns_parsed_rr rr;
|
||||
pj_in_addr ip_addr;
|
||||
|
||||
/* Add DNS entries:
|
||||
* _stun._udp.domain 60 IN SRV 0 0 PORT stun.domain.
|
||||
* stun.domain IN A 127.0.0.1
|
||||
*/
|
||||
pj_ansi_snprintf(strbuf, sizeof(strbuf),
|
||||
"_stun._udp.%s", domain);
|
||||
pj_strdup2(pool, &res_name, strbuf);
|
||||
pj_ansi_snprintf(strbuf, sizeof(strbuf),
|
||||
"stun.%s", domain);
|
||||
pj_strdup2(pool, &target, strbuf);
|
||||
pj_dns_init_srv_rr(&rr, &res_name, PJ_DNS_CLASS_IN, 60, 0, 0,
|
||||
STUN_SERVER_PORT, &target);
|
||||
pj_dns_server_add_rec(test_srv->dns_server, 1, &rr);
|
||||
|
||||
res_name = target;
|
||||
ip_addr = hostip.ipv4.sin_addr;
|
||||
pj_dns_init_a_rr(&rr, &res_name, PJ_DNS_CLASS_IN, 60, &ip_addr);
|
||||
pj_dns_server_add_rec(test_srv->dns_server, 1, &rr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (flags & CREATE_TURN_SERVER) {
|
||||
pj_activesock_cb turn_sock_cb;
|
||||
pj_sockaddr bound_addr;
|
||||
|
||||
pj_bzero(&turn_sock_cb, sizeof(turn_sock_cb));
|
||||
turn_sock_cb.on_data_recvfrom = &turn_on_data_recvfrom;
|
||||
|
||||
pj_sockaddr_in_init(&bound_addr.ipv4, NULL, TURN_SERVER_PORT);
|
||||
|
||||
status = pj_activesock_create_udp(pool, &bound_addr, NULL,
|
||||
test_srv->stun_cfg->ioqueue,
|
||||
&turn_sock_cb, test_srv,
|
||||
&test_srv->turn_sock, NULL);
|
||||
if (status != PJ_SUCCESS) {
|
||||
destroy_test_server(test_srv);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = pj_activesock_start_recvfrom(test_srv->turn_sock, pool,
|
||||
MAX_STUN_PKT, 0);
|
||||
if (status != PJ_SUCCESS) {
|
||||
destroy_test_server(test_srv);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (test_srv->dns_server && (flags & CREATE_TURN_SERVER_DNS_SRV)) {
|
||||
pj_str_t res_name, target;
|
||||
pj_dns_parsed_rr rr;
|
||||
pj_in_addr ip_addr;
|
||||
|
||||
/* Add DNS entries:
|
||||
* _turn._udp.domain 60 IN SRV 0 0 PORT turn.domain.
|
||||
* turn.domain IN A 127.0.0.1
|
||||
*/
|
||||
pj_ansi_snprintf(strbuf, sizeof(strbuf),
|
||||
"_turn._udp.%s", domain);
|
||||
pj_strdup2(pool, &res_name, strbuf);
|
||||
pj_ansi_snprintf(strbuf, sizeof(strbuf),
|
||||
"turn.%s", domain);
|
||||
pj_strdup2(pool, &target, strbuf);
|
||||
pj_dns_init_srv_rr(&rr, &res_name, PJ_DNS_CLASS_IN, 60, 0, 0,
|
||||
TURN_SERVER_PORT, &target);
|
||||
pj_dns_server_add_rec(test_srv->dns_server, 1, &rr);
|
||||
|
||||
res_name = target;
|
||||
ip_addr = hostip.ipv4.sin_addr;
|
||||
pj_dns_init_a_rr(&rr, &res_name, PJ_DNS_CLASS_IN, 60, &ip_addr);
|
||||
pj_dns_server_add_rec(test_srv->dns_server, 1, &rr);
|
||||
}
|
||||
}
|
||||
|
||||
*p_test_srv = test_srv;
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
void destroy_test_server(test_server *test_srv)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
PJ_ASSERT_ON_FAIL(test_srv, return);
|
||||
|
||||
for (i=0; i<test_srv->turn_alloc_cnt; ++i) {
|
||||
pj_activesock_close(test_srv->turn_alloc[i].sock);
|
||||
pj_pool_release(test_srv->turn_alloc[i].pool);
|
||||
}
|
||||
test_srv->turn_alloc_cnt = 0;
|
||||
|
||||
if (test_srv->turn_sock) {
|
||||
pj_activesock_close(test_srv->turn_sock);
|
||||
test_srv->turn_sock = NULL;
|
||||
}
|
||||
|
||||
if (test_srv->stun_sock) {
|
||||
pj_activesock_close(test_srv->stun_sock);
|
||||
test_srv->stun_sock = NULL;
|
||||
}
|
||||
|
||||
if (test_srv->dns_server) {
|
||||
pj_dns_server_destroy(test_srv->dns_server);
|
||||
test_srv->dns_server = NULL;
|
||||
}
|
||||
|
||||
if (test_srv->pool) {
|
||||
pj_pool_t *pool = test_srv->pool;
|
||||
test_srv->pool = NULL;
|
||||
pj_pool_release(pool);
|
||||
}
|
||||
}
|
||||
|
||||
static pj_bool_t stun_on_data_recvfrom(pj_activesock_t *asock,
|
||||
void *data,
|
||||
pj_size_t size,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
int addr_len,
|
||||
pj_status_t status)
|
||||
{
|
||||
test_server *test_srv;
|
||||
pj_stun_msg *req, *resp = NULL;
|
||||
pj_pool_t *pool;
|
||||
pj_ssize_t len;
|
||||
|
||||
if (status != PJ_SUCCESS)
|
||||
return PJ_TRUE;
|
||||
|
||||
test_srv = (test_server*) pj_activesock_get_user_data(asock);
|
||||
pool = pj_pool_create(test_srv->stun_cfg->pf, NULL, 512, 512, NULL);
|
||||
|
||||
status = pj_stun_msg_decode(pool, (pj_uint8_t*)data, size,
|
||||
PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
|
||||
&req, NULL, NULL);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_return;
|
||||
|
||||
if (req->hdr.type != PJ_STUN_BINDING_REQUEST) {
|
||||
pj_stun_msg_create_response(pool, req, PJ_STUN_SC_BAD_REQUEST,
|
||||
NULL, &resp);
|
||||
goto send_pkt;
|
||||
}
|
||||
|
||||
status = pj_stun_msg_create_response(pool, req, 0, NULL, &resp);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_return;
|
||||
|
||||
pj_stun_msg_add_sockaddr_attr(pool, resp, PJ_STUN_ATTR_XOR_MAPPED_ADDR,
|
||||
PJ_TRUE, src_addr, addr_len);
|
||||
|
||||
send_pkt:
|
||||
status = pj_stun_msg_encode(resp, (pj_uint8_t*)data, MAX_STUN_PKT,
|
||||
0, NULL, &size);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_return;
|
||||
|
||||
len = size;
|
||||
status = pj_activesock_sendto(asock, &test_srv->send_key, data, &len,
|
||||
0, src_addr, addr_len);
|
||||
|
||||
on_return:
|
||||
pj_pool_release(pool);
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
|
||||
static pj_stun_msg* create_success_response(test_server *test_srv,
|
||||
turn_allocation *alloc,
|
||||
pj_stun_msg *req,
|
||||
pj_pool_t *pool,
|
||||
unsigned lifetime,
|
||||
pj_str_t *auth_key)
|
||||
{
|
||||
pj_stun_msg *resp;
|
||||
pj_str_t tmp;
|
||||
pj_status_t status;
|
||||
|
||||
/* Create response */
|
||||
status = pj_stun_msg_create_response(pool, req, 0, NULL, &resp);
|
||||
if (status != PJ_SUCCESS) {
|
||||
return NULL;
|
||||
}
|
||||
/* Add TURN_NONCE */
|
||||
pj_stun_msg_add_string_attr(pool, resp, PJ_STUN_ATTR_NONCE, pj_cstr(&tmp, TURN_NONCE));
|
||||
/* Add LIFETIME */
|
||||
pj_stun_msg_add_uint_attr(pool, resp, PJ_STUN_ATTR_LIFETIME, lifetime);
|
||||
if (lifetime != 0) {
|
||||
/* Add RELAY-ADDRESS */
|
||||
pj_stun_msg_add_sockaddr_attr(pool, resp, PJ_STUN_ATTR_RELAY_ADDR, PJ_TRUE, &alloc->alloc_addr,
|
||||
pj_sockaddr_get_len(&alloc->alloc_addr));
|
||||
/* Add XOR-MAPPED-ADDRESS */
|
||||
pj_stun_msg_add_sockaddr_attr(pool, resp, PJ_STUN_ATTR_XOR_MAPPED_ADDR, PJ_TRUE, &alloc->client_addr,
|
||||
pj_sockaddr_get_len(&alloc->client_addr));
|
||||
}
|
||||
|
||||
/* Add blank MESSAGE-INTEGRITY */
|
||||
pj_stun_msg_add_msgint_attr(pool, resp);
|
||||
|
||||
/* Set auth key */
|
||||
pj_stun_create_key(pool, auth_key, &test_srv->domain, &test_srv->username,
|
||||
PJ_STUN_PASSWD_PLAIN, &test_srv->passwd);
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
static pj_bool_t turn_on_data_recvfrom(pj_activesock_t *asock,
|
||||
void *data,
|
||||
pj_size_t size,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
int addr_len,
|
||||
pj_status_t status)
|
||||
{
|
||||
test_server *test_srv;
|
||||
pj_pool_t *pool;
|
||||
turn_allocation *alloc;
|
||||
pj_stun_msg *req, *resp = NULL;
|
||||
pj_str_t auth_key = { NULL, 0 };
|
||||
char client_info[PJ_INET6_ADDRSTRLEN+10];
|
||||
unsigned i;
|
||||
pj_ssize_t len;
|
||||
|
||||
if (status != PJ_SUCCESS)
|
||||
return PJ_TRUE;
|
||||
|
||||
pj_sockaddr_print(src_addr, client_info, sizeof(client_info), 3);
|
||||
|
||||
test_srv = (test_server*) pj_activesock_get_user_data(asock);
|
||||
pool = pj_pool_create(test_srv->stun_cfg->pf, NULL, 512, 512, NULL);
|
||||
|
||||
status = pj_stun_msg_decode(pool, (pj_uint8_t*)data, size,
|
||||
PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET |
|
||||
PJ_STUN_NO_FINGERPRINT_CHECK,
|
||||
&req, NULL, NULL);
|
||||
if (status != PJ_SUCCESS) {
|
||||
char errmsg[PJ_ERR_MSG_SIZE];
|
||||
pj_strerror(status, errmsg, sizeof(errmsg));
|
||||
PJ_LOG(1,("", "STUN message decode error from client %s: %s", client_info, errmsg));
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/* Find the client */
|
||||
for (i=0; i<test_srv->turn_alloc_cnt; i++) {
|
||||
if (pj_sockaddr_cmp(&test_srv->turn_alloc[i].client_addr, src_addr)==0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i==test_srv->turn_alloc_cnt) {
|
||||
/* New client */
|
||||
//pj_str_t ip_addr;
|
||||
pj_stun_username_attr *uname;
|
||||
pj_activesock_cb alloc_sock_cb;
|
||||
turn_allocation *alloc;
|
||||
|
||||
/* Must be Allocate request */
|
||||
if (req->hdr.type != PJ_STUN_ALLOCATE_REQUEST) {
|
||||
PJ_LOG(1,(THIS_FILE, "Invalid %s %s from client %s",
|
||||
pj_stun_get_method_name(req->hdr.type),
|
||||
pj_stun_get_class_name(req->hdr.type),
|
||||
client_info));
|
||||
|
||||
if (PJ_STUN_IS_REQUEST(req->hdr.type))
|
||||
pj_stun_msg_create_response(pool, req, PJ_STUN_SC_BAD_REQUEST, NULL, &resp);
|
||||
goto send_pkt;
|
||||
}
|
||||
|
||||
test_srv->turn_stat.rx_allocate_cnt++;
|
||||
|
||||
/* Skip if we're not responding to Allocate request */
|
||||
if (!test_srv->turn_respond_allocate)
|
||||
return PJ_TRUE;
|
||||
|
||||
/* Check if we have too many clients */
|
||||
if (test_srv->turn_alloc_cnt == MAX_TURN_ALLOC) {
|
||||
pj_stun_msg_create_response(pool, req, PJ_STUN_SC_INSUFFICIENT_CAPACITY, NULL, &resp);
|
||||
goto send_pkt;
|
||||
}
|
||||
|
||||
/* Get USERNAME attribute */
|
||||
uname = (pj_stun_username_attr*)
|
||||
pj_stun_msg_find_attr(req, PJ_STUN_ATTR_USERNAME, 0);
|
||||
|
||||
/* Reject if it doesn't have MESSAGE-INTEGRITY or USERNAME attributes or
|
||||
* the user is incorrect
|
||||
*/
|
||||
if (pj_stun_msg_find_attr(req, PJ_STUN_ATTR_MESSAGE_INTEGRITY, 0) == NULL ||
|
||||
uname==NULL || pj_stricmp2(&uname->value, TURN_USERNAME) != 0)
|
||||
{
|
||||
pj_str_t tmp;
|
||||
|
||||
pj_stun_msg_create_response(pool, req, PJ_STUN_SC_UNAUTHORIZED, NULL, &resp);
|
||||
pj_stun_msg_add_string_attr(pool, resp, PJ_STUN_ATTR_REALM, &test_srv->domain);
|
||||
pj_stun_msg_add_string_attr(pool, resp, PJ_STUN_ATTR_NONCE, pj_cstr(&tmp, TURN_NONCE));
|
||||
goto send_pkt;
|
||||
}
|
||||
|
||||
pj_bzero(&alloc_sock_cb, sizeof(alloc_sock_cb));
|
||||
alloc_sock_cb.on_data_recvfrom = &alloc_on_data_recvfrom;
|
||||
|
||||
/* Create allocation */
|
||||
alloc = &test_srv->turn_alloc[test_srv->turn_alloc_cnt];
|
||||
alloc->perm_cnt = 0;
|
||||
alloc->test_srv = test_srv;
|
||||
pj_memcpy(&alloc->client_addr, src_addr, addr_len);
|
||||
pj_ioqueue_op_key_init(&alloc->send_key, sizeof(alloc->send_key));
|
||||
|
||||
alloc->pool = pj_pool_create(test_srv->stun_cfg->pf, "alloc", 512, 512, NULL);
|
||||
|
||||
/* Create relay socket */
|
||||
pj_sockaddr_in_init(&alloc->alloc_addr.ipv4, NULL, 0);
|
||||
pj_gethostip(pj_AF_INET(), &alloc->alloc_addr);
|
||||
|
||||
status = pj_activesock_create_udp(alloc->pool, &alloc->alloc_addr, NULL,
|
||||
test_srv->stun_cfg->ioqueue,
|
||||
&alloc_sock_cb, alloc,
|
||||
&alloc->sock, &alloc->alloc_addr);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_pool_release(alloc->pool);
|
||||
pj_stun_msg_create_response(pool, req, PJ_STUN_SC_SERVER_ERROR, NULL, &resp);
|
||||
goto send_pkt;
|
||||
}
|
||||
//pj_sockaddr_set_str_addr(pj_AF_INET(), &alloc->alloc_addr, &ip_addr);
|
||||
|
||||
pj_activesock_set_user_data(alloc->sock, alloc);
|
||||
|
||||
status = pj_activesock_start_recvfrom(alloc->sock, alloc->pool, 1500, 0);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_activesock_close(alloc->sock);
|
||||
pj_pool_release(alloc->pool);
|
||||
pj_stun_msg_create_response(pool, req, PJ_STUN_SC_SERVER_ERROR, NULL, &resp);
|
||||
goto send_pkt;
|
||||
}
|
||||
|
||||
/* Create Data indication */
|
||||
status = pj_stun_msg_create(alloc->pool, PJ_STUN_DATA_INDICATION,
|
||||
PJ_STUN_MAGIC, NULL, &alloc->data_ind);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_activesock_close(alloc->sock);
|
||||
pj_pool_release(alloc->pool);
|
||||
pj_stun_msg_create_response(pool, req, PJ_STUN_SC_SERVER_ERROR, NULL, &resp);
|
||||
goto send_pkt;
|
||||
}
|
||||
pj_stun_msg_add_sockaddr_attr(alloc->pool, alloc->data_ind,
|
||||
PJ_STUN_ATTR_PEER_ADDR, PJ_TRUE,
|
||||
&alloc->alloc_addr,
|
||||
pj_sockaddr_get_len(&alloc->alloc_addr));
|
||||
pj_stun_msg_add_binary_attr(alloc->pool, alloc->data_ind,
|
||||
PJ_STUN_ATTR_DATA, (pj_uint8_t*)"", 1);
|
||||
|
||||
/* Create response */
|
||||
resp = create_success_response(test_srv, alloc, req, pool, 600, &auth_key);
|
||||
if (resp == NULL) {
|
||||
pj_activesock_close(alloc->sock);
|
||||
pj_pool_release(alloc->pool);
|
||||
pj_stun_msg_create_response(pool, req, PJ_STUN_SC_SERVER_ERROR, NULL, &resp);
|
||||
goto send_pkt;
|
||||
}
|
||||
|
||||
++test_srv->turn_alloc_cnt;
|
||||
|
||||
} else {
|
||||
alloc = &test_srv->turn_alloc[i];
|
||||
|
||||
if (req->hdr.type == PJ_STUN_ALLOCATE_REQUEST) {
|
||||
|
||||
test_srv->turn_stat.rx_allocate_cnt++;
|
||||
|
||||
/* Skip if we're not responding to Allocate request */
|
||||
if (!test_srv->turn_respond_allocate)
|
||||
return PJ_TRUE;
|
||||
|
||||
resp = create_success_response(test_srv, alloc, req, pool, 0, &auth_key);
|
||||
|
||||
} else if (req->hdr.type == PJ_STUN_REFRESH_REQUEST) {
|
||||
pj_stun_lifetime_attr *lf_attr;
|
||||
|
||||
test_srv->turn_stat.rx_refresh_cnt++;
|
||||
|
||||
/* Skip if we're not responding to Refresh request */
|
||||
if (!test_srv->turn_respond_refresh)
|
||||
return PJ_TRUE;
|
||||
|
||||
lf_attr = (pj_stun_lifetime_attr*)
|
||||
pj_stun_msg_find_attr(req, PJ_STUN_ATTR_LIFETIME, 0);
|
||||
if (lf_attr && lf_attr->value != 0) {
|
||||
resp = create_success_response(test_srv, alloc, req, pool, 600, &auth_key);
|
||||
pj_array_erase(test_srv->turn_alloc, sizeof(test_srv->turn_alloc[0]),
|
||||
test_srv->turn_alloc_cnt, i);
|
||||
--test_srv->turn_alloc_cnt;
|
||||
} else
|
||||
resp = create_success_response(test_srv, alloc, req, pool, 0, &auth_key);
|
||||
} else if (req->hdr.type == PJ_STUN_SEND_INDICATION) {
|
||||
pj_stun_peer_addr_attr *pa;
|
||||
pj_stun_data_attr *da;
|
||||
|
||||
test_srv->turn_stat.rx_send_ind_cnt++;
|
||||
|
||||
pa = (pj_stun_peer_addr_attr*)
|
||||
pj_stun_msg_find_attr(req, PJ_STUN_ATTR_PEER_ADDR, 0);
|
||||
da = (pj_stun_data_attr*)
|
||||
pj_stun_msg_find_attr(req, PJ_STUN_ATTR_DATA, 0);
|
||||
if (pa && da) {
|
||||
unsigned j;
|
||||
char peer_info[PJ_INET6_ADDRSTRLEN];
|
||||
pj_ssize_t sent;
|
||||
|
||||
pj_sockaddr_print(&pa->sockaddr, peer_info, sizeof(peer_info), 3);
|
||||
|
||||
for (j=0; j<alloc->perm_cnt; ++j) {
|
||||
if (pj_sockaddr_cmp(&alloc->perm[j], &pa->sockaddr)==0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j==alloc->perm_cnt && alloc->perm_cnt < MAX_TURN_PERM) {
|
||||
pj_sockaddr_cp(&alloc->perm[alloc->perm_cnt], &pa->sockaddr);
|
||||
++alloc->perm_cnt;
|
||||
|
||||
PJ_LOG(5,("", "Permission %s added to client %s, perm_cnt=%d",
|
||||
peer_info, client_info, alloc->perm_cnt));
|
||||
}
|
||||
|
||||
PJ_LOG(5,(THIS_FILE, "Relaying %d bytes data from client %s to peer %s, "
|
||||
"perm_cnt=%d",
|
||||
da->length, client_info, peer_info, alloc->perm_cnt));
|
||||
|
||||
sent = da->length;
|
||||
pj_activesock_sendto(alloc->sock, &alloc->send_key,
|
||||
da->data, &sent, 0,
|
||||
&pa->sockaddr,
|
||||
pj_sockaddr_get_len(&pa->sockaddr));
|
||||
} else {
|
||||
PJ_LOG(1,(THIS_FILE, "Invalid Send Indication from %s", client_info));
|
||||
}
|
||||
} else if (PJ_STUN_IS_REQUEST(req->hdr.type)) {
|
||||
pj_stun_msg_create_response(pool, req, PJ_STUN_SC_BAD_REQUEST, NULL, &resp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
send_pkt:
|
||||
if (resp) {
|
||||
status = pj_stun_msg_encode(resp, (pj_uint8_t*)data, MAX_STUN_PKT,
|
||||
0, &auth_key, &size);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_return;
|
||||
|
||||
len = size;
|
||||
status = pj_activesock_sendto(asock, &test_srv->send_key, data, &len,
|
||||
0, src_addr, addr_len);
|
||||
}
|
||||
|
||||
on_return:
|
||||
pj_pool_release(pool);
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
/* On received data from peer */
|
||||
static pj_bool_t alloc_on_data_recvfrom(pj_activesock_t *asock,
|
||||
void *data,
|
||||
pj_size_t size,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
int addr_len,
|
||||
pj_status_t status)
|
||||
{
|
||||
turn_allocation *alloc;
|
||||
pj_stun_peer_addr_attr *pa;
|
||||
pj_stun_data_attr *da;
|
||||
char peer_info[PJ_INET6_ADDRSTRLEN+10];
|
||||
char client_info[PJ_INET6_ADDRSTRLEN+10];
|
||||
pj_uint8_t buffer[1500];
|
||||
pj_ssize_t sent;
|
||||
unsigned i;
|
||||
|
||||
if (status != PJ_SUCCESS)
|
||||
return PJ_TRUE;
|
||||
|
||||
alloc = (turn_allocation*) pj_activesock_get_user_data(asock);
|
||||
|
||||
pj_sockaddr_print(&alloc->client_addr, client_info, sizeof(client_info), 3);
|
||||
pj_sockaddr_print(src_addr, peer_info, sizeof(peer_info), 3);
|
||||
|
||||
/* Check that this peer has a permission */
|
||||
for (i=0; i<alloc->perm_cnt; ++i) {
|
||||
if (pj_sockaddr_get_len(&alloc->perm[i]) == (unsigned)addr_len &&
|
||||
pj_memcmp(pj_sockaddr_get_addr(&alloc->perm[i]),
|
||||
pj_sockaddr_get_addr(src_addr),
|
||||
addr_len) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i==alloc->perm_cnt) {
|
||||
PJ_LOG(5,("", "Client %s received %d bytes unauthorized data from peer %s",
|
||||
client_info, size, peer_info));
|
||||
if (alloc->perm_cnt == 0)
|
||||
PJ_LOG(5,("", "Client %s has no permission", client_info));
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
/* Format a Data indication */
|
||||
pa = (pj_stun_peer_addr_attr*)
|
||||
pj_stun_msg_find_attr(alloc->data_ind, PJ_STUN_ATTR_PEER_ADDR, 0);
|
||||
da = (pj_stun_data_attr*)
|
||||
pj_stun_msg_find_attr(alloc->data_ind, PJ_STUN_ATTR_DATA, 0);
|
||||
pj_assert(pa && da);
|
||||
|
||||
pj_sockaddr_cp(&pa->sockaddr, src_addr);
|
||||
da->data = data;
|
||||
da->length = size;
|
||||
|
||||
/* Encode Data indication */
|
||||
status = pj_stun_msg_encode(alloc->data_ind, buffer, sizeof(buffer), 0,
|
||||
NULL, &size);
|
||||
if (status != PJ_SUCCESS)
|
||||
return PJ_TRUE;
|
||||
|
||||
/* Send */
|
||||
sent = size;
|
||||
PJ_LOG(5,("", "Forwarding %d bytes data from peer %s to client %s",
|
||||
sent, peer_info, client_info));
|
||||
|
||||
pj_activesock_sendto(alloc->test_srv->turn_sock, &alloc->send_key, buffer,
|
||||
&sent, 0, &alloc->client_addr,
|
||||
pj_sockaddr_get_len(&alloc->client_addr));
|
||||
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
* Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef __PJNATH_TEST_SERVER_H__
|
||||
#define __PJNATH_TEST_SERVER_H__
|
||||
|
||||
#include <pjnath.h>
|
||||
#include <pjlib-util.h>
|
||||
#include <pjlib.h>
|
||||
|
||||
#define DNS_SERVER_PORT 55533
|
||||
#define STUN_SERVER_PORT 33478
|
||||
#define TURN_SERVER_PORT 33479
|
||||
|
||||
#define TURN_USERNAME "auser"
|
||||
#define TURN_PASSWD "apass"
|
||||
|
||||
#define MAX_TURN_ALLOC 16
|
||||
#define MAX_TURN_PERM 16
|
||||
|
||||
enum test_server_flags
|
||||
{
|
||||
CREATE_DNS_SERVER = (1 << 0),
|
||||
CREATE_A_RECORD_FOR_DOMAIN = (1 << 1),
|
||||
|
||||
CREATE_STUN_SERVER = (1 << 5),
|
||||
CREATE_STUN_SERVER_DNS_SRV = (1 << 6),
|
||||
|
||||
CREATE_TURN_SERVER = (1 << 10),
|
||||
CREATE_TURN_SERVER_DNS_SRV = (1 << 11),
|
||||
|
||||
};
|
||||
|
||||
typedef struct test_server test_server;
|
||||
|
||||
/* TURN allocation */
|
||||
typedef struct turn_allocation
|
||||
{
|
||||
test_server *test_srv;
|
||||
pj_pool_t *pool;
|
||||
pj_activesock_t *sock;
|
||||
pj_ioqueue_op_key_t send_key;
|
||||
pj_sockaddr client_addr;
|
||||
pj_sockaddr alloc_addr;
|
||||
unsigned perm_cnt;
|
||||
pj_sockaddr perm[MAX_TURN_PERM];
|
||||
pj_stun_msg *data_ind;
|
||||
} turn_allocation;
|
||||
|
||||
/*
|
||||
* Server installation for testing.
|
||||
* This comprises of DNS server, STUN server, and TURN server.
|
||||
*/
|
||||
struct test_server
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
pj_uint32_t flags;
|
||||
pj_stun_config *stun_cfg;
|
||||
pj_ioqueue_op_key_t send_key;
|
||||
|
||||
pj_dns_server *dns_server;
|
||||
|
||||
pj_activesock_t *stun_sock;
|
||||
|
||||
pj_activesock_t *turn_sock;
|
||||
unsigned turn_alloc_cnt;
|
||||
turn_allocation turn_alloc[MAX_TURN_ALLOC];
|
||||
pj_bool_t turn_respond_allocate;
|
||||
pj_bool_t turn_respond_refresh;
|
||||
|
||||
struct turn_stat {
|
||||
unsigned rx_allocate_cnt;
|
||||
unsigned rx_refresh_cnt;
|
||||
unsigned rx_send_ind_cnt;
|
||||
} turn_stat;
|
||||
|
||||
pj_str_t domain;
|
||||
pj_str_t username;
|
||||
pj_str_t passwd;
|
||||
|
||||
};
|
||||
|
||||
|
||||
pj_status_t create_test_server(pj_stun_config *stun_cfg,
|
||||
pj_uint32_t flags,
|
||||
const char *domain,
|
||||
test_server **p_test_srv);
|
||||
void destroy_test_server(test_server *test_srv);
|
||||
void test_server_poll_events(test_server *test_srv);
|
||||
|
||||
|
||||
#endif /* __PJNATH_TEST_SERVER_H__ */
|
||||
|
|
@ -1098,6 +1098,11 @@ int sess_auth_test(void)
|
|||
|
||||
/* If REALM doesn't match, server must respond with 401
|
||||
*/
|
||||
#if 0
|
||||
// STUN session now will just use the realm sent in the
|
||||
// response, so this test will fail because it will
|
||||
// authenticate successfully.
|
||||
|
||||
rc = run_client_test("Invalid REALM (long term)", // title
|
||||
PJ_TRUE, // server responding
|
||||
PJ_STUN_AUTH_LONG_TERM, // server auth
|
||||
|
@ -1116,6 +1121,7 @@ int sess_auth_test(void)
|
|||
if (rc != 0) {
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Invalid HMAC */
|
||||
|
||||
|
|
|
@ -0,0 +1,844 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
* Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "test.h"
|
||||
|
||||
#define THIS_FILE "stun_sock_test.c"
|
||||
|
||||
enum {
|
||||
RESPOND_STUN = 1,
|
||||
WITH_MAPPED = 2,
|
||||
WITH_XOR_MAPPED = 4,
|
||||
|
||||
ECHO = 8
|
||||
};
|
||||
|
||||
/*
|
||||
* Simple STUN server
|
||||
*/
|
||||
struct stun_srv
|
||||
{
|
||||
pj_activesock_t *asock;
|
||||
unsigned flag;
|
||||
pj_sockaddr addr;
|
||||
unsigned rx_cnt;
|
||||
pj_ioqueue_op_key_t send_key;
|
||||
pj_str_t ip_to_send;
|
||||
pj_uint16_t port_to_send;
|
||||
};
|
||||
|
||||
static pj_bool_t srv_on_data_recvfrom(pj_activesock_t *asock,
|
||||
void *data,
|
||||
pj_size_t size,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
int addr_len,
|
||||
pj_status_t status)
|
||||
{
|
||||
struct stun_srv *srv;
|
||||
pj_ssize_t sent;
|
||||
|
||||
srv = pj_activesock_get_user_data(asock);
|
||||
|
||||
/* Ignore error */
|
||||
if (status != PJ_SUCCESS)
|
||||
return PJ_TRUE;
|
||||
|
||||
++srv->rx_cnt;
|
||||
|
||||
/* Ignore if we're not responding */
|
||||
if (srv->flag & RESPOND_STUN) {
|
||||
pj_pool_t *pool;
|
||||
pj_stun_msg *req_msg, *res_msg;
|
||||
|
||||
pool = pj_pool_create(mem, "stunsrv", 512, 512, NULL);
|
||||
|
||||
/* Parse request */
|
||||
status = pj_stun_msg_decode(pool, (pj_uint8_t*)data, size,
|
||||
PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
|
||||
&req_msg, NULL, NULL);
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror(" pj_stun_msg_decode()", status);
|
||||
pj_pool_release(pool);
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
/* Create response */
|
||||
status = pj_stun_msg_create(pool, PJ_STUN_BINDING_RESPONSE, PJ_STUN_MAGIC,
|
||||
req_msg->hdr.tsx_id, &res_msg);
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror(" pj_stun_msg_create()", status);
|
||||
pj_pool_release(pool);
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
/* Add MAPPED-ADDRESS or XOR-MAPPED-ADDRESS (or don't add) */
|
||||
if (srv->flag & WITH_MAPPED) {
|
||||
pj_sockaddr_in addr;
|
||||
|
||||
pj_sockaddr_in_init(&addr, &srv->ip_to_send, srv->port_to_send);
|
||||
pj_stun_msg_add_sockaddr_attr(pool, res_msg, PJ_STUN_ATTR_MAPPED_ADDR,
|
||||
PJ_FALSE, &addr, sizeof(addr));
|
||||
} else if (srv->flag & WITH_XOR_MAPPED) {
|
||||
pj_sockaddr_in addr;
|
||||
|
||||
pj_sockaddr_in_init(&addr, &srv->ip_to_send, srv->port_to_send);
|
||||
pj_stun_msg_add_sockaddr_attr(pool, res_msg,
|
||||
PJ_STUN_ATTR_XOR_MAPPED_ADDR,
|
||||
PJ_TRUE, &addr, sizeof(addr));
|
||||
}
|
||||
|
||||
/* Encode */
|
||||
status = pj_stun_msg_encode(res_msg, (pj_uint8_t*)data, 100, 0,
|
||||
NULL, &size);
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror(" pj_stun_msg_encode()", status);
|
||||
pj_pool_release(pool);
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
/* Send back */
|
||||
sent = size;
|
||||
pj_activesock_sendto(asock, &srv->send_key, data, &sent, 0,
|
||||
src_addr, addr_len);
|
||||
|
||||
pj_pool_release(pool);
|
||||
|
||||
} else if (srv->flag & ECHO) {
|
||||
/* Send back */
|
||||
sent = size;
|
||||
pj_activesock_sendto(asock, &srv->send_key, data, &sent, 0,
|
||||
src_addr, addr_len);
|
||||
|
||||
}
|
||||
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
static pj_status_t create_server(pj_pool_t *pool,
|
||||
pj_ioqueue_t *ioqueue,
|
||||
unsigned flag,
|
||||
struct stun_srv **p_srv)
|
||||
{
|
||||
struct stun_srv *srv;
|
||||
pj_activesock_cb activesock_cb;
|
||||
pj_status_t status;
|
||||
|
||||
srv = PJ_POOL_ZALLOC_T(pool, struct stun_srv);
|
||||
srv->flag = flag;
|
||||
srv->ip_to_send = pj_str("1.1.1.1");
|
||||
srv->port_to_send = 1000;
|
||||
|
||||
status = pj_sockaddr_in_init(&srv->addr.ipv4, NULL, 0);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
pj_bzero(&activesock_cb, sizeof(activesock_cb));
|
||||
activesock_cb.on_data_recvfrom = &srv_on_data_recvfrom;
|
||||
status = pj_activesock_create_udp(pool, &srv->addr, NULL, ioqueue,
|
||||
&activesock_cb, srv, &srv->asock,
|
||||
&srv->addr);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
pj_ioqueue_op_key_init(&srv->send_key, sizeof(srv->send_key));
|
||||
|
||||
status = pj_activesock_start_recvfrom(srv->asock, pool, 512, 0);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_activesock_close(srv->asock);
|
||||
return status;
|
||||
}
|
||||
|
||||
*p_srv = srv;
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
static void destroy_server(struct stun_srv *srv)
|
||||
{
|
||||
pj_activesock_close(srv->asock);
|
||||
}
|
||||
|
||||
|
||||
struct stun_client
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
pj_stun_sock *sock;
|
||||
|
||||
pj_ioqueue_op_key_t send_key;
|
||||
pj_bool_t destroy_on_err;
|
||||
|
||||
unsigned on_status_cnt;
|
||||
pj_stun_sock_op last_op;
|
||||
pj_status_t last_status;
|
||||
|
||||
unsigned on_rx_data_cnt;
|
||||
};
|
||||
|
||||
static pj_bool_t stun_sock_on_status(pj_stun_sock *stun_sock,
|
||||
pj_stun_sock_op op,
|
||||
pj_status_t status)
|
||||
{
|
||||
struct stun_client *client;
|
||||
|
||||
client = pj_stun_sock_get_user_data(stun_sock);
|
||||
client->on_status_cnt++;
|
||||
client->last_op = op;
|
||||
client->last_status = status;
|
||||
|
||||
if (status != PJ_SUCCESS && client->destroy_on_err) {
|
||||
pj_stun_sock_destroy(client->sock);
|
||||
client->sock = NULL;
|
||||
return PJ_FALSE;
|
||||
}
|
||||
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
static pj_bool_t stun_sock_on_rx_data(pj_stun_sock *stun_sock,
|
||||
void *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
unsigned addr_len)
|
||||
{
|
||||
struct stun_client *client;
|
||||
|
||||
PJ_UNUSED_ARG(pkt);
|
||||
PJ_UNUSED_ARG(pkt_len);
|
||||
PJ_UNUSED_ARG(src_addr);
|
||||
PJ_UNUSED_ARG(addr_len);
|
||||
|
||||
client = pj_stun_sock_get_user_data(stun_sock);
|
||||
client->on_rx_data_cnt++;
|
||||
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
static pj_status_t create_client(pj_stun_config *cfg,
|
||||
struct stun_client **p_client,
|
||||
pj_bool_t destroy_on_err)
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
struct stun_client *client;
|
||||
pj_stun_sock_cfg sock_cfg;
|
||||
pj_stun_sock_cb cb;
|
||||
pj_status_t status;
|
||||
|
||||
pool = pj_pool_create(mem, "test", 512, 512, NULL);
|
||||
client = PJ_POOL_ZALLOC_T(pool, struct stun_client);
|
||||
client->pool = pool;
|
||||
|
||||
pj_stun_sock_cfg_default(&sock_cfg);
|
||||
|
||||
pj_bzero(&cb, sizeof(cb));
|
||||
cb.on_status = &stun_sock_on_status;
|
||||
cb.on_rx_data = &stun_sock_on_rx_data;
|
||||
status = pj_stun_sock_create(cfg, NULL, pj_AF_INET(), &cb,
|
||||
&sock_cfg, client, &client->sock);
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror(" pj_stun_sock_create()", status);
|
||||
pj_pool_release(pool);
|
||||
return status;
|
||||
}
|
||||
|
||||
pj_stun_sock_set_user_data(client->sock, client);
|
||||
|
||||
pj_ioqueue_op_key_init(&client->send_key, sizeof(client->send_key));
|
||||
|
||||
client->destroy_on_err = destroy_on_err;
|
||||
|
||||
*p_client = client;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void destroy_client(struct stun_client *client)
|
||||
{
|
||||
if (client->sock) {
|
||||
pj_stun_sock_destroy(client->sock);
|
||||
client->sock = NULL;
|
||||
}
|
||||
pj_pool_release(client->pool);
|
||||
}
|
||||
|
||||
static void handle_events(pj_stun_config *cfg, unsigned msec_delay)
|
||||
{
|
||||
pj_time_val delay;
|
||||
|
||||
pj_timer_heap_poll(cfg->timer_heap, NULL);
|
||||
|
||||
delay.sec = 0;
|
||||
delay.msec = msec_delay;
|
||||
pj_time_val_normalize(&delay);
|
||||
|
||||
pj_ioqueue_poll(cfg->ioqueue, &delay);
|
||||
}
|
||||
|
||||
/*
|
||||
* Timeout test: scenario when no response is received from server
|
||||
*/
|
||||
static int timeout_test(pj_stun_config *cfg, pj_bool_t destroy_on_err)
|
||||
{
|
||||
struct stun_srv *srv;
|
||||
struct stun_client *client;
|
||||
pj_str_t srv_addr;
|
||||
pj_time_val timeout, t;
|
||||
int ret = 0;
|
||||
pj_status_t status;
|
||||
|
||||
PJ_LOG(3,(THIS_FILE, " timeout test [%d]", destroy_on_err));
|
||||
|
||||
status = create_client(cfg, &client, destroy_on_err);
|
||||
if (status != PJ_SUCCESS)
|
||||
return -10;
|
||||
|
||||
status = create_server(client->pool, cfg->ioqueue, 0, &srv);
|
||||
if (status != PJ_SUCCESS) {
|
||||
destroy_client(client);
|
||||
return -20;
|
||||
}
|
||||
|
||||
srv_addr = pj_str("127.0.0.1");
|
||||
status = pj_stun_sock_start(client->sock, &srv_addr,
|
||||
pj_ntohs(srv->addr.ipv4.sin_port), NULL);
|
||||
if (status != PJ_SUCCESS) {
|
||||
destroy_server(srv);
|
||||
destroy_client(client);
|
||||
return -30;
|
||||
}
|
||||
|
||||
/* Wait until on_status() callback is called with the failure */
|
||||
pj_gettimeofday(&timeout);
|
||||
timeout.sec += 60;
|
||||
do {
|
||||
handle_events(cfg, 100);
|
||||
pj_gettimeofday(&t);
|
||||
} while (client->on_status_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
|
||||
|
||||
/* Check that callback with correct operation is called */
|
||||
if (client->last_op != PJ_STUN_SOCK_BINDING_OP) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: expecting Binding operation status"));
|
||||
ret = -40;
|
||||
goto on_return;
|
||||
}
|
||||
/* .. and with the correct status */
|
||||
if (client->last_status != PJNATH_ESTUNTIMEDOUT) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: expecting PJNATH_ESTUNTIMEDOUT"));
|
||||
ret = -50;
|
||||
goto on_return;
|
||||
}
|
||||
/* Check that server received correct retransmissions */
|
||||
if (srv->rx_cnt != PJ_STUN_MAX_TRANSMIT_COUNT) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: expecting %d retransmissions, got %d",
|
||||
PJ_STUN_MAX_TRANSMIT_COUNT, srv->rx_cnt));
|
||||
ret = -60;
|
||||
goto on_return;
|
||||
}
|
||||
/* Check that client doesn't receive anything */
|
||||
if (client->on_rx_data_cnt != 0) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: client shouldn't have received anything"));
|
||||
ret = -70;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
on_return:
|
||||
destroy_server(srv);
|
||||
destroy_client(client);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Invalid response scenario: when server returns no MAPPED-ADDRESS or
|
||||
* XOR-MAPPED-ADDRESS attribute.
|
||||
*/
|
||||
static int missing_attr_test(pj_stun_config *cfg, pj_bool_t destroy_on_err)
|
||||
{
|
||||
struct stun_srv *srv;
|
||||
struct stun_client *client;
|
||||
pj_str_t srv_addr;
|
||||
pj_time_val timeout, t;
|
||||
int ret = 0;
|
||||
pj_status_t status;
|
||||
|
||||
PJ_LOG(3,(THIS_FILE, " missing attribute test [%d]", destroy_on_err));
|
||||
|
||||
status = create_client(cfg, &client, destroy_on_err);
|
||||
if (status != PJ_SUCCESS)
|
||||
return -110;
|
||||
|
||||
status = create_server(client->pool, cfg->ioqueue, RESPOND_STUN, &srv);
|
||||
if (status != PJ_SUCCESS) {
|
||||
destroy_client(client);
|
||||
return -120;
|
||||
}
|
||||
|
||||
srv_addr = pj_str("127.0.0.1");
|
||||
status = pj_stun_sock_start(client->sock, &srv_addr,
|
||||
pj_ntohs(srv->addr.ipv4.sin_port), NULL);
|
||||
if (status != PJ_SUCCESS) {
|
||||
destroy_server(srv);
|
||||
destroy_client(client);
|
||||
return -130;
|
||||
}
|
||||
|
||||
/* Wait until on_status() callback is called with the failure */
|
||||
pj_gettimeofday(&timeout);
|
||||
timeout.sec += 60;
|
||||
do {
|
||||
handle_events(cfg, 100);
|
||||
pj_gettimeofday(&t);
|
||||
} while (client->on_status_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
|
||||
|
||||
/* Check that callback with correct operation is called */
|
||||
if (client->last_op != PJ_STUN_SOCK_BINDING_OP) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: expecting Binding operation status"));
|
||||
ret = -140;
|
||||
goto on_return;
|
||||
}
|
||||
if (client->last_status != PJNATH_ESTUNNOMAPPEDADDR) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: expecting PJNATH_ESTUNNOMAPPEDADDR"));
|
||||
ret = -150;
|
||||
goto on_return;
|
||||
}
|
||||
/* Check that client doesn't receive anything */
|
||||
if (client->on_rx_data_cnt != 0) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: client shouldn't have received anything"));
|
||||
ret = -170;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
on_return:
|
||||
destroy_server(srv);
|
||||
destroy_client(client);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Keep-alive test.
|
||||
*/
|
||||
static int keep_alive_test(pj_stun_config *cfg)
|
||||
{
|
||||
struct stun_srv *srv;
|
||||
struct stun_client *client;
|
||||
pj_sockaddr_in mapped_addr;
|
||||
pj_stun_sock_info info;
|
||||
pj_str_t srv_addr;
|
||||
pj_time_val timeout, t;
|
||||
int ret = 0;
|
||||
pj_status_t status;
|
||||
|
||||
PJ_LOG(3,(THIS_FILE, " normal operation"));
|
||||
|
||||
status = create_client(cfg, &client, PJ_TRUE);
|
||||
if (status != PJ_SUCCESS)
|
||||
return -310;
|
||||
|
||||
status = create_server(client->pool, cfg->ioqueue, RESPOND_STUN|WITH_XOR_MAPPED, &srv);
|
||||
if (status != PJ_SUCCESS) {
|
||||
destroy_client(client);
|
||||
return -320;
|
||||
}
|
||||
|
||||
/*
|
||||
* Part 1: initial Binding resolution.
|
||||
*/
|
||||
PJ_LOG(3,(THIS_FILE, " initial Binding request"));
|
||||
srv_addr = pj_str("127.0.0.1");
|
||||
status = pj_stun_sock_start(client->sock, &srv_addr,
|
||||
pj_ntohs(srv->addr.ipv4.sin_port), NULL);
|
||||
if (status != PJ_SUCCESS) {
|
||||
destroy_server(srv);
|
||||
destroy_client(client);
|
||||
return -330;
|
||||
}
|
||||
|
||||
/* Wait until on_status() callback is called with success status */
|
||||
pj_gettimeofday(&timeout);
|
||||
timeout.sec += 60;
|
||||
do {
|
||||
handle_events(cfg, 100);
|
||||
pj_gettimeofday(&t);
|
||||
} while (client->on_status_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
|
||||
|
||||
/* Check that callback with correct operation is called */
|
||||
if (client->last_op != PJ_STUN_SOCK_BINDING_OP) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: expecting Binding operation status"));
|
||||
ret = -340;
|
||||
goto on_return;
|
||||
}
|
||||
if (client->last_status != PJ_SUCCESS) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: expecting PJ_SUCCESS status"));
|
||||
ret = -350;
|
||||
goto on_return;
|
||||
}
|
||||
/* Check that client doesn't receive anything */
|
||||
if (client->on_rx_data_cnt != 0) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: client shouldn't have received anything"));
|
||||
ret = -370;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/* Get info */
|
||||
pj_bzero(&info, sizeof(info));
|
||||
pj_stun_sock_get_info(client->sock, &info);
|
||||
|
||||
/* Check that we have server address */
|
||||
if (!pj_sockaddr_has_addr(&info.srv_addr)) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: missing server address"));
|
||||
ret = -380;
|
||||
goto on_return;
|
||||
}
|
||||
/* .. and bound address port must not be zero */
|
||||
if (pj_sockaddr_get_port(&info.bound_addr)==0) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: bound address is zero"));
|
||||
ret = -381;
|
||||
goto on_return;
|
||||
}
|
||||
/* .. and mapped address */
|
||||
if (!pj_sockaddr_has_addr(&info.mapped_addr)) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: missing mapped address"));
|
||||
ret = -382;
|
||||
goto on_return;
|
||||
}
|
||||
/* verify the mapped address */
|
||||
pj_sockaddr_in_init(&mapped_addr, &srv->ip_to_send, srv->port_to_send);
|
||||
if (pj_sockaddr_cmp(&info.mapped_addr, &mapped_addr) != 0) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: mapped address mismatched"));
|
||||
ret = -383;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/* .. and at least one alias */
|
||||
if (info.alias_cnt == 0) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: must have at least one alias"));
|
||||
ret = -384;
|
||||
goto on_return;
|
||||
}
|
||||
if (!pj_sockaddr_has_addr(&info.aliases[0])) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: missing alias"));
|
||||
ret = -386;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Part 2: sending and receiving data
|
||||
*/
|
||||
PJ_LOG(3,(THIS_FILE, " sending/receiving data"));
|
||||
|
||||
/* Change server operation mode to echo back data */
|
||||
srv->flag = ECHO;
|
||||
|
||||
/* Reset server */
|
||||
srv->rx_cnt = 0;
|
||||
|
||||
/* Client sending data to echo server */
|
||||
{
|
||||
char txt[100];
|
||||
PJ_LOG(3,(THIS_FILE, " sending to %s", pj_sockaddr_print(&info.srv_addr, txt, sizeof(txt), 3)));
|
||||
}
|
||||
status = pj_stun_sock_sendto(client->sock, NULL, &ret, sizeof(ret),
|
||||
0, &info.srv_addr,
|
||||
pj_sockaddr_get_len(&info.srv_addr));
|
||||
if (status != PJ_SUCCESS && status != PJ_EPENDING) {
|
||||
app_perror(" error: server sending data", status);
|
||||
ret = -390;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/* Wait for a short period until client receives data. We can't wait for
|
||||
* too long otherwise the keep-alive will kick in.
|
||||
*/
|
||||
pj_gettimeofday(&timeout);
|
||||
timeout.sec += 1;
|
||||
do {
|
||||
handle_events(cfg, 100);
|
||||
pj_gettimeofday(&t);
|
||||
} while (client->on_rx_data_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
|
||||
|
||||
/* Check that data is received in server */
|
||||
if (srv->rx_cnt == 0) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: server didn't receive data"));
|
||||
ret = -395;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/* Check that status is still OK */
|
||||
if (client->last_status != PJ_SUCCESS) {
|
||||
app_perror(" error: client has failed", client->last_status);
|
||||
ret = -400;
|
||||
goto on_return;
|
||||
}
|
||||
/* Check that data has been received */
|
||||
if (client->on_rx_data_cnt == 0) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: client doesn't receive data"));
|
||||
ret = -410;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Part 3: Successful keep-alive,
|
||||
*/
|
||||
PJ_LOG(3,(THIS_FILE, " successful keep-alive scenario"));
|
||||
|
||||
/* Change server operation mode to normal mode */
|
||||
srv->flag = RESPOND_STUN | WITH_XOR_MAPPED;
|
||||
|
||||
/* Reset server */
|
||||
srv->rx_cnt = 0;
|
||||
|
||||
/* Reset client */
|
||||
client->on_status_cnt = 0;
|
||||
client->last_status = PJ_SUCCESS;
|
||||
client->on_rx_data_cnt = 0;
|
||||
|
||||
/* Wait for keep-alive duration to see if client actually sends the
|
||||
* keep-alive.
|
||||
*/
|
||||
pj_gettimeofday(&timeout);
|
||||
timeout.sec += (PJ_STUN_KEEP_ALIVE_SEC + 1);
|
||||
do {
|
||||
handle_events(cfg, 100);
|
||||
pj_gettimeofday(&t);
|
||||
} while (PJ_TIME_VAL_LT(t, timeout));
|
||||
|
||||
/* Check that server receives some packets */
|
||||
if (srv->rx_cnt == 0) {
|
||||
PJ_LOG(3, (THIS_FILE, " error: no keep-alive was received"));
|
||||
ret = -420;
|
||||
goto on_return;
|
||||
}
|
||||
/* Check that client status is still okay and on_status() callback is NOT
|
||||
* called
|
||||
*/
|
||||
if (client->on_status_cnt != 0) {
|
||||
PJ_LOG(3, (THIS_FILE, " error: on_status() must not be called on successful"
|
||||
"keep-alive when mapped-address does not change"));
|
||||
ret = -430;
|
||||
goto on_return;
|
||||
}
|
||||
/* Check that client doesn't receive anything */
|
||||
if (client->on_rx_data_cnt != 0) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: client shouldn't have received anything"));
|
||||
ret = -440;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Part 4: Successful keep-alive with IP address change
|
||||
*/
|
||||
PJ_LOG(3,(THIS_FILE, " mapped IP address change"));
|
||||
|
||||
/* Change server operation mode to normal mode */
|
||||
srv->flag = RESPOND_STUN | WITH_XOR_MAPPED;
|
||||
|
||||
/* Change mapped address in the response */
|
||||
srv->ip_to_send = pj_str("2.2.2.2");
|
||||
srv->port_to_send++;
|
||||
|
||||
/* Reset server */
|
||||
srv->rx_cnt = 0;
|
||||
|
||||
/* Reset client */
|
||||
client->on_status_cnt = 0;
|
||||
client->last_status = PJ_SUCCESS;
|
||||
client->on_rx_data_cnt = 0;
|
||||
|
||||
/* Wait for keep-alive duration to see if client actually sends the
|
||||
* keep-alive.
|
||||
*/
|
||||
pj_gettimeofday(&timeout);
|
||||
timeout.sec += (PJ_STUN_KEEP_ALIVE_SEC + 1);
|
||||
do {
|
||||
handle_events(cfg, 100);
|
||||
pj_gettimeofday(&t);
|
||||
} while (PJ_TIME_VAL_LT(t, timeout));
|
||||
|
||||
/* Check that server receives some packets */
|
||||
if (srv->rx_cnt == 0) {
|
||||
PJ_LOG(3, (THIS_FILE, " error: no keep-alive was received"));
|
||||
ret = -450;
|
||||
goto on_return;
|
||||
}
|
||||
/* Check that on_status() callback is called (because mapped address
|
||||
* has changed)
|
||||
*/
|
||||
if (client->on_status_cnt != 1) {
|
||||
PJ_LOG(3, (THIS_FILE, " error: on_status() was not called"));
|
||||
ret = -460;
|
||||
goto on_return;
|
||||
}
|
||||
/* Check that callback was called with correct operation */
|
||||
if (client->last_op != PJ_STUN_SOCK_KEEP_ALIVE_OP) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: expecting keep-alive operation status"));
|
||||
ret = -470;
|
||||
goto on_return;
|
||||
}
|
||||
/* Check that last status is still success */
|
||||
if (client->last_status != PJ_SUCCESS) {
|
||||
PJ_LOG(3, (THIS_FILE, " error: expecting successful status"));
|
||||
ret = -480;
|
||||
goto on_return;
|
||||
}
|
||||
/* Check that client doesn't receive anything */
|
||||
if (client->on_rx_data_cnt != 0) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: client shouldn't have received anything"));
|
||||
ret = -490;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/* Get info */
|
||||
pj_bzero(&info, sizeof(info));
|
||||
pj_stun_sock_get_info(client->sock, &info);
|
||||
|
||||
/* Check that we have server address */
|
||||
if (!pj_sockaddr_has_addr(&info.srv_addr)) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: missing server address"));
|
||||
ret = -500;
|
||||
goto on_return;
|
||||
}
|
||||
/* .. and mapped address */
|
||||
if (!pj_sockaddr_has_addr(&info.mapped_addr)) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: missing mapped address"));
|
||||
ret = -510;
|
||||
goto on_return;
|
||||
}
|
||||
/* verify the mapped address */
|
||||
pj_sockaddr_in_init(&mapped_addr, &srv->ip_to_send, srv->port_to_send);
|
||||
if (pj_sockaddr_cmp(&info.mapped_addr, &mapped_addr) != 0) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: mapped address mismatched"));
|
||||
ret = -520;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/* .. and at least one alias */
|
||||
if (info.alias_cnt == 0) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: must have at least one alias"));
|
||||
ret = -530;
|
||||
goto on_return;
|
||||
}
|
||||
if (!pj_sockaddr_has_addr(&info.aliases[0])) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: missing alias"));
|
||||
ret = -540;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Part 5: Failed keep-alive
|
||||
*/
|
||||
PJ_LOG(3,(THIS_FILE, " failed keep-alive scenario"));
|
||||
|
||||
/* Change server operation mode to respond without attribute */
|
||||
srv->flag = RESPOND_STUN;
|
||||
|
||||
/* Reset server */
|
||||
srv->rx_cnt = 0;
|
||||
|
||||
/* Reset client */
|
||||
client->on_status_cnt = 0;
|
||||
client->last_status = PJ_SUCCESS;
|
||||
client->on_rx_data_cnt = 0;
|
||||
|
||||
/* Wait until on_status() is called with failure. */
|
||||
pj_gettimeofday(&timeout);
|
||||
timeout.sec += (PJ_STUN_KEEP_ALIVE_SEC + PJ_STUN_TIMEOUT_VALUE + 5);
|
||||
do {
|
||||
handle_events(cfg, 100);
|
||||
pj_gettimeofday(&t);
|
||||
} while (client->on_status_cnt==0 && PJ_TIME_VAL_LT(t, timeout));
|
||||
|
||||
/* Check that callback with correct operation is called */
|
||||
if (client->last_op != PJ_STUN_SOCK_KEEP_ALIVE_OP) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: expecting keep-alive operation status"));
|
||||
ret = -600;
|
||||
goto on_return;
|
||||
}
|
||||
if (client->last_status == PJ_SUCCESS) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: expecting failed keep-alive"));
|
||||
ret = -610;
|
||||
goto on_return;
|
||||
}
|
||||
/* Check that client doesn't receive anything */
|
||||
if (client->on_rx_data_cnt != 0) {
|
||||
PJ_LOG(3,(THIS_FILE, " error: client shouldn't have received anything"));
|
||||
ret = -620;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
|
||||
on_return:
|
||||
destroy_server(srv);
|
||||
destroy_client(client);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#define DO_TEST(expr) \
|
||||
capture_pjlib_state(&stun_cfg, &pjlib_state); \
|
||||
ret = expr; \
|
||||
if (ret != 0) goto on_return; \
|
||||
ret = check_pjlib_state(&stun_cfg, &pjlib_state); \
|
||||
if (ret != 0) goto on_return;
|
||||
|
||||
|
||||
int stun_sock_test(void)
|
||||
{
|
||||
struct pjlib_state pjlib_state;
|
||||
pj_stun_config stun_cfg;
|
||||
pj_ioqueue_t *ioqueue = NULL;
|
||||
pj_timer_heap_t *timer_heap = NULL;
|
||||
pj_pool_t *pool = NULL;
|
||||
pj_status_t status;
|
||||
int ret = 0;
|
||||
|
||||
pool = pj_pool_create(mem, NULL, 512, 512, NULL);
|
||||
|
||||
status = pj_ioqueue_create(pool, 12, &ioqueue);
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror(" pj_ioqueue_create()", status);
|
||||
ret = -4;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
status = pj_timer_heap_create(pool, 100, &timer_heap);
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror(" pj_timer_heap_create()", status);
|
||||
ret = -8;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
pj_stun_config_init(&stun_cfg, mem, 0, ioqueue, timer_heap);
|
||||
|
||||
DO_TEST(timeout_test(&stun_cfg, PJ_FALSE));
|
||||
DO_TEST(timeout_test(&stun_cfg, PJ_TRUE));
|
||||
|
||||
DO_TEST(missing_attr_test(&stun_cfg, PJ_FALSE));
|
||||
DO_TEST(missing_attr_test(&stun_cfg, PJ_TRUE));
|
||||
|
||||
DO_TEST(keep_alive_test(&stun_cfg));
|
||||
|
||||
on_return:
|
||||
if (timer_heap) pj_timer_heap_destroy(timer_heap);
|
||||
if (ioqueue) pj_ioqueue_destroy(ioqueue);
|
||||
if (pool) pj_pool_release(pool);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -29,6 +29,109 @@ void app_perror(const char *msg, pj_status_t rc)
|
|||
PJ_LOG(1,("test", "%s: [pj_status_t=%d] %s", msg, rc, errbuf));
|
||||
}
|
||||
|
||||
pj_status_t create_stun_config(pj_pool_t *pool, pj_stun_config *stun_cfg)
|
||||
{
|
||||
pj_ioqueue_t *ioqueue;
|
||||
pj_timer_heap_t *timer_heap;
|
||||
pj_status_t status;
|
||||
|
||||
status = pj_ioqueue_create(pool, 64, &ioqueue);
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror(" pj_ioqueue_create()", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = pj_timer_heap_create(pool, 256, &timer_heap);
|
||||
if (status != PJ_SUCCESS) {
|
||||
app_perror(" pj_timer_heap_create()", status);
|
||||
pj_ioqueue_destroy(ioqueue);
|
||||
return status;
|
||||
}
|
||||
|
||||
pj_stun_config_init(stun_cfg, mem, 0, ioqueue, timer_heap);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
void destroy_stun_config(pj_stun_config *stun_cfg)
|
||||
{
|
||||
if (stun_cfg->timer_heap) {
|
||||
pj_timer_heap_destroy(stun_cfg->timer_heap);
|
||||
stun_cfg->timer_heap = NULL;
|
||||
}
|
||||
if (stun_cfg->ioqueue) {
|
||||
pj_ioqueue_destroy(stun_cfg->ioqueue);
|
||||
stun_cfg->ioqueue = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void poll_events(pj_stun_config *stun_cfg, unsigned msec,
|
||||
pj_bool_t first_event_only)
|
||||
{
|
||||
pj_time_val stop_time;
|
||||
int count = 0;
|
||||
|
||||
pj_gettimeofday(&stop_time);
|
||||
stop_time.msec += msec;
|
||||
pj_time_val_normalize(&stop_time);
|
||||
|
||||
/* Process all events for the specified duration. */
|
||||
for (;;) {
|
||||
pj_time_val timeout = {0, 1}, now;
|
||||
int c;
|
||||
|
||||
c = pj_timer_heap_poll( stun_cfg->timer_heap, NULL );
|
||||
if (c > 0)
|
||||
count += c;
|
||||
|
||||
//timeout.sec = timeout.msec = 0;
|
||||
c = pj_ioqueue_poll( stun_cfg->ioqueue, &timeout);
|
||||
if (c > 0)
|
||||
count += c;
|
||||
|
||||
pj_gettimeofday(&now);
|
||||
if (PJ_TIME_VAL_GTE(now, stop_time))
|
||||
break;
|
||||
|
||||
if (first_event_only && count >= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void capture_pjlib_state(pj_stun_config *cfg, struct pjlib_state *st)
|
||||
{
|
||||
pj_caching_pool *cp;
|
||||
|
||||
st->timer_cnt = pj_timer_heap_count(cfg->timer_heap);
|
||||
|
||||
cp = (pj_caching_pool*)mem;
|
||||
st->pool_used_cnt = cp->used_count;
|
||||
}
|
||||
|
||||
int check_pjlib_state(pj_stun_config *cfg,
|
||||
const struct pjlib_state *initial_st)
|
||||
{
|
||||
struct pjlib_state current_state;
|
||||
int rc = 0;
|
||||
|
||||
capture_pjlib_state(cfg, ¤t_state);
|
||||
|
||||
if (current_state.timer_cnt > initial_st->timer_cnt) {
|
||||
PJ_LOG(3,("", " error: possibly leaking timer"));
|
||||
rc |= ERR_TIMER_LEAK;
|
||||
}
|
||||
|
||||
if (current_state.pool_used_cnt > initial_st->pool_used_cnt) {
|
||||
PJ_LOG(3,("", " error: possibly leaking memory"));
|
||||
PJ_LOG(3,("", " dumping memory pool:"));
|
||||
pj_pool_factory_dump(mem, PJ_TRUE);
|
||||
rc |= ERR_MEMORY_LEAK;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
#define DO_TEST(test) do { \
|
||||
PJ_LOG(3, ("test", "Running %s...", #test)); \
|
||||
rc = test; \
|
||||
|
@ -64,6 +167,7 @@ static int test_inner(void)
|
|||
pj_dump_config();
|
||||
pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 );
|
||||
|
||||
pjlib_util_init();
|
||||
pjnath_init();
|
||||
|
||||
#if INCLUDE_STUN_TEST
|
||||
|
@ -75,6 +179,14 @@ static int test_inner(void)
|
|||
DO_TEST(ice_test());
|
||||
#endif
|
||||
|
||||
#if INCLUDE_STUN_SOCK_TEST
|
||||
DO_TEST(stun_sock_test());
|
||||
#endif
|
||||
|
||||
#if INCLUDE_TURN_SOCK_TEST
|
||||
DO_TEST(turn_sock_test());
|
||||
#endif
|
||||
|
||||
on_return:
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -22,12 +22,41 @@
|
|||
|
||||
#define INCLUDE_STUN_TEST 1
|
||||
#define INCLUDE_ICE_TEST 1
|
||||
#define INCLUDE_STUN_SOCK_TEST 1
|
||||
#define INCLUDE_TURN_SOCK_TEST 1
|
||||
|
||||
int stun_test(void);
|
||||
int sess_auth_test(void);
|
||||
int stun_sock_test(void);
|
||||
int turn_sock_test(void);
|
||||
int ice_test(void);
|
||||
int test_main(void);
|
||||
|
||||
extern void app_perror(const char *title, pj_status_t rc);
|
||||
extern pj_pool_factory *mem;
|
||||
|
||||
////////////////////////////////////
|
||||
/*
|
||||
* Utilities
|
||||
*/
|
||||
pj_status_t create_stun_config(pj_pool_t *pool, pj_stun_config *stun_cfg);
|
||||
void destroy_stun_config(pj_stun_config *stun_cfg);
|
||||
|
||||
void poll_events(pj_stun_config *stun_cfg, unsigned msec,
|
||||
pj_bool_t first_event_only);
|
||||
|
||||
typedef struct pjlib_state
|
||||
{
|
||||
unsigned timer_cnt; /* Number of timer entries */
|
||||
unsigned pool_used_cnt; /* Number of app pools */
|
||||
} pjlib_state;
|
||||
|
||||
|
||||
void capture_pjlib_state(pj_stun_config *cfg, struct pjlib_state *st);
|
||||
int check_pjlib_state(pj_stun_config *cfg,
|
||||
const struct pjlib_state *initial_st);
|
||||
|
||||
|
||||
#define ERR_MEMORY_LEAK 1
|
||||
#define ERR_TIMER_LEAK 2
|
||||
|
||||
|
|
|
@ -0,0 +1,515 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
* Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "test.h"
|
||||
#include "server.h"
|
||||
|
||||
#define SRV_DOMAIN "pjsip.lab.domain"
|
||||
#define KA_INTERVAL 50
|
||||
|
||||
struct test_result
|
||||
{
|
||||
unsigned state_called;
|
||||
unsigned rx_data_cnt;
|
||||
};
|
||||
|
||||
struct test_session
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
pj_stun_config *stun_cfg;
|
||||
pj_turn_sock *turn_sock;
|
||||
pj_dns_resolver *resolver;
|
||||
test_server *test_srv;
|
||||
|
||||
pj_bool_t destroy_called;
|
||||
int destroy_on_state;
|
||||
struct test_result result;
|
||||
};
|
||||
|
||||
struct test_session_cfg
|
||||
{
|
||||
struct {
|
||||
pj_bool_t enable_dns_srv;
|
||||
int destroy_on_state;
|
||||
} client;
|
||||
|
||||
struct {
|
||||
pj_uint32_t flags;
|
||||
pj_bool_t respond_allocate;
|
||||
pj_bool_t respond_refresh;
|
||||
} srv;
|
||||
};
|
||||
|
||||
static void turn_on_rx_data(pj_turn_sock *turn_sock,
|
||||
void *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *peer_addr,
|
||||
unsigned addr_len);
|
||||
static void turn_on_state(pj_turn_sock *turn_sock,
|
||||
pj_turn_state_t old_state,
|
||||
pj_turn_state_t new_state);
|
||||
|
||||
static void destroy_session(struct test_session *sess)
|
||||
{
|
||||
if (sess->resolver) {
|
||||
pj_dns_resolver_destroy(sess->resolver, PJ_TRUE);
|
||||
sess->resolver = NULL;
|
||||
}
|
||||
|
||||
if (sess->turn_sock) {
|
||||
if (!sess->destroy_called) {
|
||||
sess->destroy_called = PJ_TRUE;
|
||||
pj_turn_sock_destroy(sess->turn_sock);
|
||||
}
|
||||
sess->turn_sock = NULL;
|
||||
}
|
||||
|
||||
if (sess->test_srv) {
|
||||
destroy_test_server(sess->test_srv);
|
||||
sess->test_srv = NULL;
|
||||
}
|
||||
|
||||
if (sess->pool) {
|
||||
pj_pool_release(sess->pool);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int create_test_session(pj_stun_config *stun_cfg,
|
||||
const struct test_session_cfg *cfg,
|
||||
struct test_session **p_sess)
|
||||
{
|
||||
struct test_session *sess;
|
||||
pj_pool_t *pool;
|
||||
pj_turn_sock_cb turn_sock_cb;
|
||||
pj_turn_alloc_param alloc_param;
|
||||
pj_stun_auth_cred cred;
|
||||
pj_status_t status;
|
||||
|
||||
/* Create client */
|
||||
pool = pj_pool_create(mem, "turnclient", 512, 512, NULL);
|
||||
sess = PJ_POOL_ZALLOC_T(pool, struct test_session);
|
||||
sess->pool = pool;
|
||||
sess->stun_cfg = stun_cfg;
|
||||
sess->destroy_on_state = cfg->client.destroy_on_state;
|
||||
|
||||
pj_bzero(&turn_sock_cb, sizeof(turn_sock_cb));
|
||||
turn_sock_cb.on_rx_data = &turn_on_rx_data;
|
||||
turn_sock_cb.on_state = &turn_on_state;
|
||||
status = pj_turn_sock_create(sess->stun_cfg, pj_AF_INET(), PJ_TURN_TP_UDP,
|
||||
&turn_sock_cb, 0, sess, &sess->turn_sock);
|
||||
if (status != PJ_SUCCESS) {
|
||||
destroy_session(sess);
|
||||
return -20;
|
||||
}
|
||||
|
||||
/* Create test server */
|
||||
status = create_test_server(sess->stun_cfg, cfg->srv.flags,
|
||||
SRV_DOMAIN, &sess->test_srv);
|
||||
if (status != PJ_SUCCESS) {
|
||||
destroy_session(sess);
|
||||
return -30;
|
||||
}
|
||||
|
||||
sess->test_srv->turn_respond_allocate = cfg->srv.respond_allocate;
|
||||
sess->test_srv->turn_respond_refresh = cfg->srv.respond_refresh;
|
||||
|
||||
/* Create client resolver */
|
||||
status = pj_dns_resolver_create(mem, "resolver", 0, sess->stun_cfg->timer_heap,
|
||||
sess->stun_cfg->ioqueue, &sess->resolver);
|
||||
if (status != PJ_SUCCESS) {
|
||||
destroy_session(sess);
|
||||
return -40;
|
||||
|
||||
} else {
|
||||
pj_str_t dns_srv = pj_str("127.0.0.1");
|
||||
pj_uint16_t dns_srv_port = (pj_uint16_t) DNS_SERVER_PORT;
|
||||
status = pj_dns_resolver_set_ns(sess->resolver, 1, &dns_srv, &dns_srv_port);
|
||||
|
||||
if (status != PJ_SUCCESS) {
|
||||
destroy_session(sess);
|
||||
return -50;
|
||||
}
|
||||
}
|
||||
|
||||
/* Init TURN credential */
|
||||
pj_bzero(&cred, sizeof(cred));
|
||||
cred.type = PJ_STUN_AUTH_CRED_STATIC;
|
||||
cred.data.static_cred.realm = pj_str(SRV_DOMAIN);
|
||||
cred.data.static_cred.username = pj_str(TURN_USERNAME);
|
||||
cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN;
|
||||
cred.data.static_cred.data = pj_str(TURN_PASSWD);
|
||||
|
||||
/* Init TURN allocate parameter */
|
||||
pj_turn_alloc_param_default(&alloc_param);
|
||||
alloc_param.ka_interval = KA_INTERVAL;
|
||||
|
||||
/* Start the client */
|
||||
if (cfg->client.enable_dns_srv) {
|
||||
/* Use DNS SRV to resolve server, may fallback to DNS A */
|
||||
pj_str_t domain = pj_str(SRV_DOMAIN);
|
||||
status = pj_turn_sock_alloc(sess->turn_sock, &domain, TURN_SERVER_PORT,
|
||||
sess->resolver, &cred, &alloc_param);
|
||||
|
||||
} else {
|
||||
/* Explicitly specify server address */
|
||||
pj_str_t host = pj_str("127.0.0.1");
|
||||
status = pj_turn_sock_alloc(sess->turn_sock, &host, TURN_SERVER_PORT,
|
||||
NULL, &cred, &alloc_param);
|
||||
|
||||
}
|
||||
|
||||
if (status != PJ_SUCCESS) {
|
||||
if (cfg->client.destroy_on_state >= PJ_TURN_STATE_READY) {
|
||||
destroy_session(sess);
|
||||
return -70;
|
||||
}
|
||||
}
|
||||
|
||||
*p_sess = sess;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void turn_on_rx_data(pj_turn_sock *turn_sock,
|
||||
void *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *peer_addr,
|
||||
unsigned addr_len)
|
||||
{
|
||||
struct test_session *sess;
|
||||
|
||||
PJ_UNUSED_ARG(pkt);
|
||||
PJ_UNUSED_ARG(pkt_len);
|
||||
PJ_UNUSED_ARG(peer_addr);
|
||||
PJ_UNUSED_ARG(addr_len);
|
||||
|
||||
sess = (struct test_session*) pj_turn_sock_get_user_data(turn_sock);
|
||||
if (sess == NULL)
|
||||
return;
|
||||
|
||||
sess->result.rx_data_cnt++;
|
||||
}
|
||||
|
||||
|
||||
static void turn_on_state(pj_turn_sock *turn_sock,
|
||||
pj_turn_state_t old_state,
|
||||
pj_turn_state_t new_state)
|
||||
{
|
||||
struct test_session *sess;
|
||||
unsigned i, mask;
|
||||
|
||||
PJ_UNUSED_ARG(old_state);
|
||||
|
||||
sess = (struct test_session*) pj_turn_sock_get_user_data(turn_sock);
|
||||
if (sess == NULL)
|
||||
return;
|
||||
|
||||
/* This state must not be called before */
|
||||
pj_assert((sess->result.state_called & (1<<new_state)) == 0);
|
||||
|
||||
/* new_state must be greater than old_state */
|
||||
pj_assert(new_state > old_state);
|
||||
|
||||
/* must not call any greater state before */
|
||||
mask = 0;
|
||||
for (i=new_state+1; i<31; ++i) mask |= (1 << i);
|
||||
|
||||
pj_assert((sess->result.state_called & mask) == 0);
|
||||
|
||||
sess->result.state_called |= (1 << new_state);
|
||||
|
||||
if (new_state >= sess->destroy_on_state && !sess->destroy_called) {
|
||||
sess->destroy_called = PJ_TRUE;
|
||||
pj_turn_sock_destroy(turn_sock);
|
||||
}
|
||||
|
||||
if (new_state >= PJ_TURN_STATE_DESTROYING) {
|
||||
pj_turn_sock_set_user_data(sess->turn_sock, NULL);
|
||||
sess->turn_sock = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int state_progression_test(pj_stun_config *stun_cfg)
|
||||
{
|
||||
struct test_session_cfg test_cfg =
|
||||
{
|
||||
{ /* Client cfg */
|
||||
/* DNS SRV */ /* Destroy on state */
|
||||
PJ_TRUE, 0xFFFF
|
||||
},
|
||||
{ /* Server cfg */
|
||||
0xFFFFFFFF, /* flags */
|
||||
PJ_TRUE, /* respond to allocate */
|
||||
PJ_TRUE /* respond to refresh */
|
||||
}
|
||||
};
|
||||
struct test_session *sess;
|
||||
unsigned i;
|
||||
int rc;
|
||||
|
||||
PJ_LOG(3,("", " state progression tests"));
|
||||
|
||||
for (i=0; i<=1; ++i) {
|
||||
enum { TIMEOUT = 60 };
|
||||
pjlib_state pjlib_state;
|
||||
pj_turn_session_info info;
|
||||
struct test_result result;
|
||||
pj_time_val tstart;
|
||||
|
||||
PJ_LOG(3,("", " %s DNS SRV resolution",
|
||||
(i==0? "without" : "with")));
|
||||
|
||||
capture_pjlib_state(stun_cfg, &pjlib_state);
|
||||
|
||||
test_cfg.client.enable_dns_srv = i;
|
||||
|
||||
rc = create_test_session(stun_cfg, &test_cfg, &sess);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
pj_bzero(&info, sizeof(info));
|
||||
|
||||
/* Wait until state is READY */
|
||||
pj_gettimeofday(&tstart);
|
||||
while (sess->turn_sock) {
|
||||
pj_time_val now;
|
||||
|
||||
poll_events(stun_cfg, 10, PJ_FALSE);
|
||||
rc = pj_turn_sock_get_info(sess->turn_sock, &info);
|
||||
if (rc!=PJ_SUCCESS)
|
||||
break;
|
||||
|
||||
if (info.state >= PJ_TURN_STATE_READY)
|
||||
break;
|
||||
|
||||
pj_gettimeofday(&now);
|
||||
if (now.sec - tstart.sec > TIMEOUT) {
|
||||
PJ_LOG(3,("", " timed-out"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (info.state != PJ_TURN_STATE_READY) {
|
||||
PJ_LOG(3,("", " error: state is not READY"));
|
||||
destroy_session(sess);
|
||||
return -130;
|
||||
}
|
||||
|
||||
/* Deallocate */
|
||||
pj_turn_sock_destroy(sess->turn_sock);
|
||||
|
||||
/* Wait for couple of seconds.
|
||||
* We can't poll the session info since the session may have
|
||||
* been destroyed
|
||||
*/
|
||||
poll_events(stun_cfg, 2000, PJ_FALSE);
|
||||
sess->turn_sock = NULL;
|
||||
pj_memcpy(&result, &sess->result, sizeof(result));
|
||||
destroy_session(sess);
|
||||
|
||||
/* Check the result */
|
||||
if ((result.state_called & (1<<PJ_TURN_STATE_RESOLVING)) == 0) {
|
||||
PJ_LOG(3,("", " error: PJ_TURN_STATE_RESOLVING is not called"));
|
||||
return -140;
|
||||
}
|
||||
|
||||
if ((result.state_called & (1<<PJ_TURN_STATE_RESOLVED)) == 0) {
|
||||
PJ_LOG(3,("", " error: PJ_TURN_STATE_RESOLVED is not called"));
|
||||
return -150;
|
||||
}
|
||||
|
||||
if ((result.state_called & (1<<PJ_TURN_STATE_ALLOCATING)) == 0) {
|
||||
PJ_LOG(3,("", " error: PJ_TURN_STATE_ALLOCATING is not called"));
|
||||
return -155;
|
||||
}
|
||||
|
||||
if ((result.state_called & (1<<PJ_TURN_STATE_READY)) == 0) {
|
||||
PJ_LOG(3,("", " error: PJ_TURN_STATE_READY is not called"));
|
||||
return -160;
|
||||
}
|
||||
|
||||
if ((result.state_called & (1<<PJ_TURN_STATE_DEALLOCATING)) == 0) {
|
||||
PJ_LOG(3,("", " error: PJ_TURN_STATE_DEALLOCATING is not called"));
|
||||
return -170;
|
||||
}
|
||||
|
||||
if ((result.state_called & (1<<PJ_TURN_STATE_DEALLOCATED)) == 0) {
|
||||
PJ_LOG(3,("", " error: PJ_TURN_STATE_DEALLOCATED is not called"));
|
||||
return -180;
|
||||
}
|
||||
|
||||
if ((result.state_called & (1<<PJ_TURN_STATE_DESTROYING)) == 0) {
|
||||
PJ_LOG(3,("", " error: PJ_TURN_STATE_DESTROYING is not called"));
|
||||
return -190;
|
||||
}
|
||||
|
||||
poll_events(stun_cfg, 500, PJ_FALSE);
|
||||
rc = check_pjlib_state(stun_cfg, &pjlib_state);
|
||||
if (rc != 0) {
|
||||
PJ_LOG(3,("", " error: memory/timer-heap leak detected"));
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int destroy_test(pj_stun_config *stun_cfg,
|
||||
pj_bool_t with_dns_srv,
|
||||
pj_bool_t in_callback)
|
||||
{
|
||||
struct test_session_cfg test_cfg =
|
||||
{
|
||||
{ /* Client cfg */
|
||||
/* DNS SRV */ /* Destroy on state */
|
||||
PJ_TRUE, 0xFFFF
|
||||
},
|
||||
{ /* Server cfg */
|
||||
0xFFFFFFFF, /* flags */
|
||||
PJ_TRUE, /* respond to allocate */
|
||||
PJ_TRUE /* respond to refresh */
|
||||
}
|
||||
};
|
||||
struct test_session *sess;
|
||||
int target_state;
|
||||
int rc;
|
||||
|
||||
PJ_LOG(3,("", " destroy test %s %s",
|
||||
(in_callback? "in callback" : ""),
|
||||
(with_dns_srv? "with DNS srv" : "")
|
||||
));
|
||||
|
||||
test_cfg.client.enable_dns_srv = with_dns_srv;
|
||||
|
||||
for (target_state=PJ_TURN_STATE_RESOLVING; target_state<=PJ_TURN_STATE_READY; ++target_state) {
|
||||
enum { TIMEOUT = 60 };
|
||||
pjlib_state pjlib_state;
|
||||
pj_turn_session_info info;
|
||||
pj_time_val tstart;
|
||||
|
||||
capture_pjlib_state(stun_cfg, &pjlib_state);
|
||||
|
||||
PJ_LOG(3,("", " %s", pj_turn_state_name((pj_turn_state_t)target_state)));
|
||||
|
||||
if (in_callback)
|
||||
test_cfg.client.destroy_on_state = target_state;
|
||||
|
||||
rc = create_test_session(stun_cfg, &test_cfg, &sess);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
if (in_callback) {
|
||||
pj_gettimeofday(&tstart);
|
||||
rc = 0;
|
||||
while (sess->turn_sock) {
|
||||
pj_time_val now;
|
||||
|
||||
poll_events(stun_cfg, 100, PJ_FALSE);
|
||||
|
||||
pj_gettimeofday(&now);
|
||||
if (now.sec - tstart.sec > TIMEOUT) {
|
||||
rc = -7;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
pj_gettimeofday(&tstart);
|
||||
rc = 0;
|
||||
while (sess->turn_sock) {
|
||||
pj_time_val now;
|
||||
|
||||
poll_events(stun_cfg, 1, PJ_FALSE);
|
||||
|
||||
pj_turn_sock_get_info(sess->turn_sock, &info);
|
||||
|
||||
if (info.state >= target_state) {
|
||||
pj_turn_sock_destroy(sess->turn_sock);
|
||||
break;
|
||||
}
|
||||
|
||||
pj_gettimeofday(&now);
|
||||
if (now.sec - tstart.sec > TIMEOUT) {
|
||||
rc = -8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (rc != 0) {
|
||||
PJ_LOG(3,("", " error: timeout"));
|
||||
return rc;
|
||||
}
|
||||
|
||||
poll_events(stun_cfg, 1000, PJ_FALSE);
|
||||
destroy_session(sess);
|
||||
|
||||
rc = check_pjlib_state(stun_cfg, &pjlib_state);
|
||||
if (rc != 0) {
|
||||
PJ_LOG(3,("", " error: memory/timer-heap leak detected"));
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
int turn_sock_test(void)
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
pj_stun_config stun_cfg;
|
||||
int i, rc = 0;
|
||||
|
||||
pool = pj_pool_create(mem, "turntest", 512, 512, NULL);
|
||||
rc = create_stun_config(pool, &stun_cfg);
|
||||
if (rc != PJ_SUCCESS) {
|
||||
pj_pool_release(pool);
|
||||
return -2;
|
||||
}
|
||||
|
||||
rc = state_progression_test(&stun_cfg);
|
||||
if (rc != 0)
|
||||
goto on_return;
|
||||
|
||||
for (i=0; i<=1; ++i) {
|
||||
int j;
|
||||
for (j=0; j<=1; ++j) {
|
||||
rc = destroy_test(&stun_cfg, i, j);
|
||||
if (rc != 0)
|
||||
goto on_return;
|
||||
}
|
||||
}
|
||||
|
||||
on_return:
|
||||
destroy_stun_config(&stun_cfg);
|
||||
pj_pool_release(pool);
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -52,6 +52,8 @@ static const struct
|
|||
PJ_BUILD_ERR( PJNATH_ESTUNIPV6NOTSUPP, "STUN IPv6 attribute not supported"),
|
||||
PJ_BUILD_ERR( PJNATH_ESTUNINSERVER, "Invalid STUN server or server not configured"),
|
||||
|
||||
PJ_BUILD_ERR( PJNATH_ESTUNDESTROYED, "STUN object has been destoyed"),
|
||||
|
||||
/* ICE related errors */
|
||||
PJ_BUILD_ERR( PJNATH_ENOICE, "ICE session not available"),
|
||||
PJ_BUILD_ERR( PJNATH_EICEINPROGRESS, "ICE check is in progress"),
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <pj/array.h>
|
||||
#include <pj/assert.h>
|
||||
#include <pj/guid.h>
|
||||
#include <pj/hash.h>
|
||||
#include <pj/log.h>
|
||||
#include <pj/os.h>
|
||||
#include <pj/pool.h>
|
||||
|
@ -101,6 +102,11 @@ typedef struct timer_data
|
|||
} timer_data;
|
||||
|
||||
|
||||
/* This is the data that will be attached as token to outgoing
|
||||
* STUN messages.
|
||||
*/
|
||||
|
||||
|
||||
/* Forward declarations */
|
||||
static void destroy_ice(pj_ice_sess *ice,
|
||||
pj_status_t reason);
|
||||
|
@ -169,6 +175,21 @@ PJ_DEF(const char*) pj_ice_get_cand_type_name(pj_ice_cand_type type)
|
|||
}
|
||||
|
||||
|
||||
PJ_DEF(const char*) pj_ice_sess_role_name(pj_ice_sess_role role)
|
||||
{
|
||||
switch (role) {
|
||||
case PJ_ICE_SESS_ROLE_UNKNOWN:
|
||||
return "Unknown";
|
||||
case PJ_ICE_SESS_ROLE_CONTROLLED:
|
||||
return "Controlled";
|
||||
case PJ_ICE_SESS_ROLE_CONTROLLING:
|
||||
return "Controlling";
|
||||
default:
|
||||
return "??";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Get the prefix for the foundation */
|
||||
static int get_type_prefix(pj_ice_cand_type type)
|
||||
{
|
||||
|
@ -183,17 +204,28 @@ static int get_type_prefix(pj_ice_cand_type type)
|
|||
}
|
||||
}
|
||||
|
||||
/* Calculate foundation */
|
||||
/* Calculate foundation:
|
||||
* Two candidates have the same foundation when they are "similar" - of
|
||||
* the same type and obtained from the same host candidate and STUN
|
||||
* server using the same protocol. Otherwise, their foundation is
|
||||
* different.
|
||||
*/
|
||||
PJ_DEF(void) pj_ice_calc_foundation(pj_pool_t *pool,
|
||||
pj_str_t *foundation,
|
||||
pj_ice_cand_type type,
|
||||
const pj_sockaddr *base_addr)
|
||||
{
|
||||
char buf[64];
|
||||
pj_uint32_t val;
|
||||
|
||||
if (base_addr->addr.sa_family == pj_AF_INET()) {
|
||||
val = pj_ntohl(base_addr->ipv4.sin_addr.s_addr);
|
||||
} else {
|
||||
val = pj_hash_calc(0, pj_sockaddr_get_addr(base_addr),
|
||||
pj_sockaddr_get_addr_len(base_addr));
|
||||
}
|
||||
pj_ansi_snprintf(buf, sizeof(buf), "%c%x",
|
||||
get_type_prefix(type),
|
||||
(int)pj_ntohl(base_addr->ipv4.sin_addr.s_addr));
|
||||
get_type_prefix(type), val);
|
||||
pj_strdup2(pool, foundation, buf);
|
||||
}
|
||||
|
||||
|
@ -263,7 +295,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_create(pj_stun_config *stun_cfg,
|
|||
PJ_ASSERT_RETURN(stun_cfg && cb && p_ice, PJ_EINVAL);
|
||||
|
||||
if (name == NULL)
|
||||
name = "ice%p";
|
||||
name = "icess%p";
|
||||
|
||||
pool = pj_pool_create(stun_cfg->pf, name, PJNATH_POOL_LEN_ICE_SESS,
|
||||
PJNATH_POOL_INC_ICE_SESS, NULL);
|
||||
|
@ -300,6 +332,12 @@ PJ_DEF(pj_status_t) pj_ice_sess_create(pj_stun_config *stun_cfg,
|
|||
}
|
||||
}
|
||||
|
||||
/* Initialize transport datas */
|
||||
for (i=0; i<PJ_ARRAY_SIZE(ice->tp_data); ++i) {
|
||||
ice->tp_data[i].transport_id = i;
|
||||
ice->tp_data[i].has_req_data = PJ_FALSE;
|
||||
}
|
||||
|
||||
if (local_ufrag == NULL) {
|
||||
ice->rx_ufrag.ptr = (char*) pj_pool_alloc(ice->pool, PJ_ICE_UFRAG_LEN);
|
||||
pj_create_random_string(ice->rx_ufrag.ptr, PJ_ICE_UFRAG_LEN);
|
||||
|
@ -551,6 +589,7 @@ static pj_uint32_t CALC_CAND_PRIO(pj_ice_sess *ice,
|
|||
*/
|
||||
PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
|
||||
unsigned comp_id,
|
||||
unsigned transport_id,
|
||||
pj_ice_cand_type type,
|
||||
pj_uint16_t local_pref,
|
||||
const pj_str_t *foundation,
|
||||
|
@ -576,17 +615,14 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
|
|||
}
|
||||
|
||||
lcand = &ice->lcand[ice->lcand_cnt];
|
||||
lcand->comp_id = comp_id;
|
||||
lcand->comp_id = (pj_uint8_t)comp_id;
|
||||
lcand->transport_id = (pj_uint8_t)transport_id;
|
||||
lcand->type = type;
|
||||
pj_strdup(ice->pool, &lcand->foundation, foundation);
|
||||
lcand->prio = CALC_CAND_PRIO(ice, type, local_pref, lcand->comp_id);
|
||||
pj_memcpy(&lcand->addr, addr, addr_len);
|
||||
pj_memcpy(&lcand->base_addr, base_addr, addr_len);
|
||||
if (rel_addr)
|
||||
pj_memcpy(&lcand->rel_addr, rel_addr, addr_len);
|
||||
else
|
||||
pj_bzero(&lcand->rel_addr, sizeof(lcand->rel_addr));
|
||||
|
||||
pj_memcpy(&lcand->rel_addr, rel_addr, addr_len);
|
||||
|
||||
pj_ansi_strcpy(ice->tmp.txt, pj_inet_ntoa(lcand->addr.ipv4.sin_addr));
|
||||
LOG4((ice->obj_name,
|
||||
|
@ -1322,9 +1358,13 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list(
|
|||
}
|
||||
|
||||
/* Disable our components which don't have matching component */
|
||||
if (ice->comp_cnt==2 && highest_comp==1) {
|
||||
ice->comp_cnt = 1;
|
||||
for (i=highest_comp; i<ice->comp_cnt; ++i) {
|
||||
if (ice->comp[i].stun_sess) {
|
||||
pj_stun_session_destroy(ice->comp[i].stun_sess);
|
||||
pj_bzero(&ice->comp[i], sizeof(ice->comp[i]));
|
||||
}
|
||||
}
|
||||
ice->comp_cnt = highest_comp;
|
||||
|
||||
/* Init timer entry in the checklist. Initially the timer ID is FALSE
|
||||
* because timer is not running.
|
||||
|
@ -1345,26 +1385,13 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list(
|
|||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* This is the data that will be attached as user data to outgoing
|
||||
* STUN requests, and it will be given back when we receive completion
|
||||
* status of the request.
|
||||
*/
|
||||
struct req_data
|
||||
{
|
||||
pj_ice_sess *ice;
|
||||
pj_ice_sess_checklist *clist;
|
||||
unsigned ckid;
|
||||
};
|
||||
|
||||
|
||||
/* Perform check on the specified candidate pair */
|
||||
static pj_status_t perform_check(pj_ice_sess *ice,
|
||||
pj_ice_sess_checklist *clist,
|
||||
unsigned check_id)
|
||||
{
|
||||
pj_ice_sess_comp *comp;
|
||||
struct req_data *rd;
|
||||
pj_ice_msg_data *msg_data;
|
||||
pj_ice_sess_check *check;
|
||||
const pj_ice_sess_cand *lcand;
|
||||
const pj_ice_sess_cand *rcand;
|
||||
|
@ -1392,10 +1419,12 @@ static pj_status_t perform_check(pj_ice_sess *ice,
|
|||
/* Attach data to be retrieved later when STUN request transaction
|
||||
* completes and on_stun_request_complete() callback is called.
|
||||
*/
|
||||
rd = PJ_POOL_ZALLOC_T(check->tdata->pool, struct req_data);
|
||||
rd->ice = ice;
|
||||
rd->clist = clist;
|
||||
rd->ckid = check_id;
|
||||
msg_data = PJ_POOL_ZALLOC_T(check->tdata->pool, pj_ice_msg_data);
|
||||
msg_data->transport_id = lcand->transport_id;
|
||||
msg_data->has_req_data = PJ_TRUE;
|
||||
msg_data->data.req.ice = ice;
|
||||
msg_data->data.req.clist = clist;
|
||||
msg_data->data.req.ckid = check_id;
|
||||
|
||||
/* Add PRIORITY */
|
||||
prio = CALC_CAND_PRIO(ice, PJ_ICE_CAND_TYPE_PRFLX, 65535,
|
||||
|
@ -1427,7 +1456,7 @@ static pj_status_t perform_check(pj_ice_sess *ice,
|
|||
*/
|
||||
|
||||
/* Initiate STUN transaction to send the request */
|
||||
status = pj_stun_session_send_msg(comp->stun_sess, (void*)rd, PJ_FALSE,
|
||||
status = pj_stun_session_send_msg(comp->stun_sess, msg_data, PJ_FALSE,
|
||||
PJ_TRUE, &rcand->addr,
|
||||
sizeof(pj_sockaddr_in), check->tdata);
|
||||
if (status != PJ_SUCCESS) {
|
||||
|
@ -1655,12 +1684,10 @@ static pj_status_t on_stun_send_msg(pj_stun_session *sess,
|
|||
{
|
||||
stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess);
|
||||
pj_ice_sess *ice = sd->ice;
|
||||
|
||||
PJ_UNUSED_ARG(token);
|
||||
|
||||
return (*ice->cb.on_tx_pkt)(ice, sd->comp_id,
|
||||
pkt, pkt_size,
|
||||
dst_addr, addr_len);
|
||||
pj_ice_msg_data *msg_data = (pj_ice_msg_data*) token;
|
||||
|
||||
return (*ice->cb.on_tx_pkt)(ice, sd->comp_id, msg_data->transport_id,
|
||||
pkt, pkt_size, dst_addr, addr_len);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1673,7 +1700,7 @@ static void on_stun_request_complete(pj_stun_session *stun_sess,
|
|||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len)
|
||||
{
|
||||
struct req_data *rd = (struct req_data*) token;
|
||||
pj_ice_msg_data *msg_data = (pj_ice_msg_data*) token;
|
||||
pj_ice_sess *ice;
|
||||
pj_ice_sess_check *check, *new_check;
|
||||
pj_ice_sess_cand *lcand;
|
||||
|
@ -1684,9 +1711,12 @@ static void on_stun_request_complete(pj_stun_session *stun_sess,
|
|||
PJ_UNUSED_ARG(stun_sess);
|
||||
PJ_UNUSED_ARG(src_addr_len);
|
||||
|
||||
ice = rd->ice;
|
||||
check = &rd->clist->checks[rd->ckid];
|
||||
clist = rd->clist;
|
||||
pj_assert(msg_data->has_req_data);
|
||||
|
||||
ice = msg_data->data.req.ice;
|
||||
clist = msg_data->data.req.clist;
|
||||
check = &clist->checks[msg_data->data.req.ckid];
|
||||
|
||||
|
||||
/* Mark STUN transaction as complete */
|
||||
pj_assert(tdata == check->tdata);
|
||||
|
@ -1739,7 +1769,7 @@ static void on_stun_request_complete(pj_stun_session *stun_sess,
|
|||
/* Resend request */
|
||||
LOG4((ice->obj_name, "Resending check because of role conflict"));
|
||||
check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_WAITING, 0);
|
||||
perform_check(ice, clist, rd->ckid);
|
||||
perform_check(ice, clist, msg_data->data.req.ckid);
|
||||
pj_mutex_unlock(ice->mutex);
|
||||
return;
|
||||
}
|
||||
|
@ -1846,6 +1876,7 @@ static void on_stun_request_complete(pj_stun_session *stun_sess,
|
|||
|
||||
/* Add new peer reflexive candidate */
|
||||
status = pj_ice_sess_add_cand(ice, check->lcand->comp_id,
|
||||
msg_data->transport_id,
|
||||
PJ_ICE_CAND_TYPE_PRFLX,
|
||||
65535, &foundation,
|
||||
&xaddr->sockaddr,
|
||||
|
@ -1919,6 +1950,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
|
|||
{
|
||||
stun_data *sd;
|
||||
const pj_stun_msg *msg = rdata->msg;
|
||||
pj_ice_msg_data *msg_data;
|
||||
pj_ice_sess *ice;
|
||||
pj_stun_priority_attr *prio_attr;
|
||||
pj_stun_use_candidate_attr *uc_attr;
|
||||
|
@ -1929,12 +1961,11 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
|
|||
|
||||
PJ_UNUSED_ARG(pkt);
|
||||
PJ_UNUSED_ARG(pkt_len);
|
||||
PJ_UNUSED_ARG(token);
|
||||
|
||||
|
||||
/* Reject any requests except Binding request */
|
||||
if (msg->hdr.type != PJ_STUN_BINDING_REQUEST) {
|
||||
pj_stun_session_respond(sess, rdata, PJ_STUN_SC_BAD_REQUEST,
|
||||
NULL, NULL, PJ_TRUE,
|
||||
NULL, token, PJ_TRUE,
|
||||
src_addr, src_addr_len);
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
@ -2001,7 +2032,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
|
|||
} else {
|
||||
/* Generate 487 response */
|
||||
pj_stun_session_respond(sess, rdata, PJ_STUN_SC_ROLE_CONFLICT,
|
||||
NULL, NULL, PJ_TRUE,
|
||||
NULL, token, PJ_TRUE,
|
||||
src_addr, src_addr_len);
|
||||
pj_mutex_unlock(ice->mutex);
|
||||
return PJ_SUCCESS;
|
||||
|
@ -2013,7 +2044,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
|
|||
if (pj_cmp_timestamp(&ice->tie_breaker, &role_attr->value) < 0) {
|
||||
/* Generate 487 response */
|
||||
pj_stun_session_respond(sess, rdata, PJ_STUN_SC_ROLE_CONFLICT,
|
||||
NULL, NULL, PJ_TRUE,
|
||||
NULL, token, PJ_TRUE,
|
||||
src_addr, src_addr_len);
|
||||
pj_mutex_unlock(ice->mutex);
|
||||
return PJ_SUCCESS;
|
||||
|
@ -2034,11 +2065,18 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
|
|||
return status;
|
||||
}
|
||||
|
||||
/* Add XOR-MAPPED-ADDRESS attribute */
|
||||
status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
|
||||
PJ_STUN_ATTR_XOR_MAPPED_ADDR,
|
||||
PJ_TRUE, src_addr, src_addr_len);
|
||||
|
||||
status = pj_stun_session_send_msg(sess, NULL, PJ_TRUE, PJ_TRUE,
|
||||
/* Create a msg_data to be associated with this response */
|
||||
msg_data = PJ_POOL_ZALLOC_T(tdata->pool, pj_ice_msg_data);
|
||||
msg_data->transport_id = ((pj_ice_msg_data*)token)->transport_id;
|
||||
msg_data->has_req_data = PJ_FALSE;
|
||||
|
||||
/* Send the response */
|
||||
status = pj_stun_session_send_msg(sess, msg_data, PJ_TRUE, PJ_TRUE,
|
||||
src_addr, src_addr_len, tdata);
|
||||
|
||||
|
||||
|
@ -2058,6 +2096,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
|
|||
|
||||
/* Init rcheck */
|
||||
rcheck->comp_id = sd->comp_id;
|
||||
rcheck->transport_id = ((pj_ice_msg_data*)token)->transport_id;
|
||||
rcheck->src_addr_len = src_addr_len;
|
||||
pj_memcpy(&rcheck->src_addr, src_addr, src_addr_len);
|
||||
rcheck->use_candidate = (uc_attr != NULL);
|
||||
|
@ -2090,7 +2129,6 @@ static void handle_incoming_check(pj_ice_sess *ice,
|
|||
pj_ice_sess_cand *lcand = NULL;
|
||||
pj_ice_sess_cand *rcand;
|
||||
unsigned i;
|
||||
pj_bool_t is_relayed;
|
||||
|
||||
comp = find_comp(ice, rcheck->comp_id);
|
||||
|
||||
|
@ -2109,7 +2147,7 @@ static void handle_incoming_check(pj_ice_sess *ice,
|
|||
*/
|
||||
if (i == ice->rcand_cnt) {
|
||||
rcand = &ice->rcand[ice->rcand_cnt++];
|
||||
rcand->comp_id = rcheck->comp_id;
|
||||
rcand->comp_id = (pj_uint8_t)rcheck->comp_id;
|
||||
rcand->type = PJ_ICE_CAND_TYPE_PRFLX;
|
||||
rcand->prio = rcheck->priority;
|
||||
pj_memcpy(&rcand->addr, &rcheck->src_addr, rcheck->src_addr_len);
|
||||
|
@ -2147,12 +2185,14 @@ static void handle_incoming_check(pj_ice_sess *ice,
|
|||
}
|
||||
}
|
||||
#else
|
||||
/* Just get candidate with the highest priority for the specified
|
||||
* component ID in the checklist.
|
||||
/* Just get candidate with the highest priority and same transport ID
|
||||
* for the specified component ID in the checklist.
|
||||
*/
|
||||
for (i=0; i<ice->clist.count; ++i) {
|
||||
pj_ice_sess_check *c = &ice->clist.checks[i];
|
||||
if (c->lcand->comp_id == rcheck->comp_id) {
|
||||
if (c->lcand->comp_id == rcheck->comp_id &&
|
||||
c->lcand->transport_id == rcheck->transport_id)
|
||||
{
|
||||
lcand = c->lcand;
|
||||
break;
|
||||
}
|
||||
|
@ -2170,11 +2210,6 @@ static void handle_incoming_check(pj_ice_sess *ice,
|
|||
/*
|
||||
* Create candidate pair for this request.
|
||||
*/
|
||||
/* First check if the source address is the source address of the
|
||||
* STUN relay, to determine if local candidate is relayed candidate.
|
||||
*/
|
||||
PJ_TODO(DETERMINE_IF_REQUEST_COMES_FROM_RELAYED_CANDIDATE);
|
||||
is_relayed = PJ_FALSE;
|
||||
|
||||
/*
|
||||
* 7.2.1.4. Triggered Checks
|
||||
|
@ -2309,6 +2344,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_send_data(pj_ice_sess *ice,
|
|||
{
|
||||
pj_status_t status = PJ_SUCCESS;
|
||||
pj_ice_sess_comp *comp;
|
||||
pj_ice_sess_cand *cand;
|
||||
|
||||
PJ_ASSERT_RETURN(ice && comp_id, PJ_EINVAL);
|
||||
|
||||
|
@ -2332,7 +2368,9 @@ PJ_DEF(pj_status_t) pj_ice_sess_send_data(pj_ice_sess *ice,
|
|||
goto on_return;
|
||||
}
|
||||
|
||||
status = (*ice->cb.on_tx_pkt)(ice, comp_id, data, data_len,
|
||||
cand = comp->valid_check->lcand;
|
||||
status = (*ice->cb.on_tx_pkt)(ice, comp_id, cand->transport_id,
|
||||
data, data_len,
|
||||
&comp->valid_check->rcand->addr,
|
||||
sizeof(pj_sockaddr_in));
|
||||
|
||||
|
@ -2344,6 +2382,7 @@ on_return:
|
|||
|
||||
PJ_DEF(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice,
|
||||
unsigned comp_id,
|
||||
unsigned transport_id,
|
||||
void *pkt,
|
||||
pj_size_t pkt_size,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
|
@ -2351,6 +2390,8 @@ PJ_DEF(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice,
|
|||
{
|
||||
pj_status_t status = PJ_SUCCESS;
|
||||
pj_ice_sess_comp *comp;
|
||||
pj_ice_msg_data *msg_data = NULL;
|
||||
unsigned i;
|
||||
pj_status_t stun_status;
|
||||
|
||||
PJ_ASSERT_RETURN(ice, PJ_EINVAL);
|
||||
|
@ -2363,11 +2404,24 @@ PJ_DEF(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice,
|
|||
goto on_return;
|
||||
}
|
||||
|
||||
/* Find transport */
|
||||
for (i=0; i<PJ_ARRAY_SIZE(ice->tp_data); ++i) {
|
||||
if (ice->tp_data[i].transport_id == transport_id) {
|
||||
msg_data = &ice->tp_data[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (msg_data == NULL) {
|
||||
pj_assert(!"Invalid transport ID");
|
||||
status = PJ_EINVAL;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
stun_status = pj_stun_msg_check((const pj_uint8_t*)pkt, pkt_size,
|
||||
PJ_STUN_IS_DATAGRAM);
|
||||
if (stun_status == PJ_SUCCESS) {
|
||||
status = pj_stun_session_on_rx_pkt(comp->stun_sess, pkt, pkt_size,
|
||||
PJ_STUN_IS_DATAGRAM, NULL,
|
||||
PJ_STUN_IS_DATAGRAM, msg_data,
|
||||
NULL, src_addr, src_addr_len);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_strerror(status, ice->tmp.errmsg, sizeof(ice->tmp.errmsg));
|
||||
|
@ -2375,7 +2429,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice,
|
|||
ice->tmp.errmsg));
|
||||
}
|
||||
} else {
|
||||
(*ice->cb.on_rx_data)(ice, comp_id, pkt, pkt_size,
|
||||
(*ice->cb.on_rx_data)(ice, comp_id, transport_id, pkt, pkt_size,
|
||||
src_addr, src_addr_len);
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1557,7 +1557,7 @@ PJ_DEF(pj_status_t) pj_stun_unknown_attr_create(pj_pool_t *pool,
|
|||
/* Create and add STUN UNKNOWN-ATTRIBUTES attribute to the message. */
|
||||
PJ_DEF(pj_status_t) pj_stun_msg_add_unknown_attr(pj_pool_t *pool,
|
||||
pj_stun_msg *msg,
|
||||
unsigned attr_cnt,
|
||||
pj_size_t attr_cnt,
|
||||
const pj_uint16_t attr_types[])
|
||||
{
|
||||
pj_stun_unknown_attr *attr = NULL;
|
||||
|
@ -1646,7 +1646,7 @@ static void* clone_unknown_attr(pj_pool_t *pool, const void *src)
|
|||
PJ_DEF(pj_status_t) pj_stun_binary_attr_create(pj_pool_t *pool,
|
||||
int attr_type,
|
||||
const pj_uint8_t *data,
|
||||
unsigned length,
|
||||
pj_size_t length,
|
||||
pj_stun_binary_attr **p_attr)
|
||||
{
|
||||
pj_stun_binary_attr *attr;
|
||||
|
@ -1673,7 +1673,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_binary_attr(pj_pool_t *pool,
|
|||
pj_stun_msg *msg,
|
||||
int attr_type,
|
||||
const pj_uint8_t *data,
|
||||
unsigned length)
|
||||
pj_size_t length)
|
||||
{
|
||||
pj_stun_binary_attr *attr = NULL;
|
||||
pj_status_t status;
|
||||
|
@ -1833,10 +1833,10 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_attr(pj_stun_msg *msg,
|
|||
/*
|
||||
* Check that the PDU is potentially a valid STUN message.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pj_stun_msg_check(const pj_uint8_t *pdu, unsigned pdu_len,
|
||||
PJ_DEF(pj_status_t) pj_stun_msg_check(const pj_uint8_t *pdu, pj_size_t pdu_len,
|
||||
unsigned options)
|
||||
{
|
||||
unsigned msg_len;
|
||||
pj_size_t msg_len;
|
||||
|
||||
PJ_ASSERT_RETURN(pdu, PJ_EINVAL);
|
||||
|
||||
|
@ -1938,10 +1938,10 @@ PJ_DEF(pj_status_t) pj_stun_msg_create_response(pj_pool_t *pool,
|
|||
*/
|
||||
PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
|
||||
const pj_uint8_t *pdu,
|
||||
unsigned pdu_len,
|
||||
pj_size_t pdu_len,
|
||||
unsigned options,
|
||||
pj_stun_msg **p_msg,
|
||||
unsigned *p_parsed_len,
|
||||
pj_size_t *p_parsed_len,
|
||||
pj_stun_msg **p_response)
|
||||
{
|
||||
|
||||
|
@ -2190,9 +2190,9 @@ static char *print_binary(const pj_uint8_t *data, unsigned data_len)
|
|||
*/
|
||||
PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
|
||||
pj_uint8_t *buf, unsigned buf_size,
|
||||
unsigned options,
|
||||
pj_size_t options,
|
||||
const pj_str_t *key,
|
||||
unsigned *p_msg_len)
|
||||
pj_size_t *p_msg_len)
|
||||
{
|
||||
pj_uint8_t *start = buf;
|
||||
pj_stun_msgint_attr *amsgint = NULL;
|
||||
|
|
|
@ -29,14 +29,23 @@ struct pj_stun_session
|
|||
pj_stun_session_cb cb;
|
||||
void *user_data;
|
||||
|
||||
pj_atomic_t *busy;
|
||||
pj_bool_t destroy_request;
|
||||
|
||||
pj_bool_t use_fingerprint;
|
||||
|
||||
pj_pool_t *rx_pool;
|
||||
|
||||
#if PJ_LOG_MAX_LEVEL >= 5
|
||||
char dump_buf[1000];
|
||||
#endif
|
||||
unsigned log_flag;
|
||||
|
||||
pj_stun_auth_type auth_type;
|
||||
pj_stun_auth_cred cred;
|
||||
int auth_retry;
|
||||
pj_str_t next_nonce;
|
||||
pj_str_t server_realm;
|
||||
|
||||
pj_str_t srv_name;
|
||||
|
||||
|
@ -79,7 +88,7 @@ static pj_stun_tsx_cb tsx_cb =
|
|||
static pj_status_t tsx_add(pj_stun_session *sess,
|
||||
pj_stun_tx_data *tdata)
|
||||
{
|
||||
pj_list_push_back(&sess->pending_request_list, tdata);
|
||||
pj_list_push_front(&sess->pending_request_list, tdata);
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -138,11 +147,13 @@ static void stun_tsx_on_destroy(pj_stun_client_tsx *tsx)
|
|||
pj_stun_tx_data *tdata;
|
||||
|
||||
tdata = (pj_stun_tx_data*) pj_stun_client_tsx_get_data(tsx);
|
||||
tsx_erase(tdata->sess, tdata);
|
||||
|
||||
pj_stun_client_tsx_destroy(tsx);
|
||||
pj_pool_release(tdata->pool);
|
||||
}
|
||||
|
||||
static void destroy_tdata(pj_stun_tx_data *tdata)
|
||||
static void destroy_tdata(pj_stun_tx_data *tdata, pj_bool_t force)
|
||||
{
|
||||
if (tdata->res_timer.id != PJ_FALSE) {
|
||||
pj_timer_heap_cancel(tdata->sess->cfg->timer_heap,
|
||||
|
@ -151,14 +162,21 @@ static void destroy_tdata(pj_stun_tx_data *tdata)
|
|||
pj_list_erase(tdata);
|
||||
}
|
||||
|
||||
if (tdata->client_tsx) {
|
||||
pj_time_val delay = {2, 0};
|
||||
tsx_erase(tdata->sess, tdata);
|
||||
pj_stun_client_tsx_schedule_destroy(tdata->client_tsx, &delay);
|
||||
tdata->client_tsx = NULL;
|
||||
if (force) {
|
||||
if (tdata->client_tsx) {
|
||||
tsx_erase(tdata->sess, tdata);
|
||||
pj_stun_client_tsx_destroy(tdata->client_tsx);
|
||||
}
|
||||
pj_pool_release(tdata->pool);
|
||||
|
||||
} else {
|
||||
pj_pool_release(tdata->pool);
|
||||
if (tdata->client_tsx) {
|
||||
pj_time_val delay = {2, 0};
|
||||
pj_stun_client_tsx_schedule_destroy(tdata->client_tsx, &delay);
|
||||
|
||||
} else {
|
||||
pj_pool_release(tdata->pool);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,7 +187,7 @@ PJ_DEF(void) pj_stun_msg_destroy_tdata( pj_stun_session *sess,
|
|||
pj_stun_tx_data *tdata)
|
||||
{
|
||||
PJ_UNUSED_ARG(sess);
|
||||
destroy_tdata(tdata);
|
||||
destroy_tdata(tdata, PJ_FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
@ -289,6 +307,7 @@ static pj_status_t handle_auth_challenge(pj_stun_session *sess,
|
|||
ea->err_code == PJ_STUN_SC_STALE_NONCE)
|
||||
{
|
||||
const pj_stun_nonce_attr *anonce;
|
||||
const pj_stun_realm_attr *arealm;
|
||||
pj_stun_tx_data *tdata;
|
||||
unsigned i;
|
||||
pj_status_t status;
|
||||
|
@ -316,6 +335,13 @@ static pj_status_t handle_auth_challenge(pj_stun_session *sess,
|
|||
/* Save next_nonce */
|
||||
pj_strdup(sess->pool, &sess->next_nonce, &anonce->value);
|
||||
|
||||
/* Copy the realm from the response */
|
||||
arealm = (pj_stun_realm_attr*)
|
||||
pj_stun_msg_find_attr(response, PJ_STUN_ATTR_REALM, 0);
|
||||
if (arealm) {
|
||||
pj_strdup(sess->pool, &sess->server_realm, &arealm->value);
|
||||
}
|
||||
|
||||
/* Create new request */
|
||||
status = pj_stun_session_create_req(sess, request->msg->hdr.type,
|
||||
request->msg->hdr.magic,
|
||||
|
@ -324,7 +350,8 @@ static pj_status_t handle_auth_challenge(pj_stun_session *sess,
|
|||
return status;
|
||||
|
||||
/* Duplicate all the attributes in the old request, except
|
||||
* USERNAME, REALM, M-I, and NONCE
|
||||
* USERNAME, REALM, M-I, and NONCE, which will be filled in
|
||||
* later.
|
||||
*/
|
||||
for (i=0; i<request->msg->attr_count; ++i) {
|
||||
const pj_stun_attr_hdr *asrc = request->msg->attr[i];
|
||||
|
@ -373,6 +400,10 @@ static void stun_tsx_on_complete(pj_stun_client_tsx *tsx,
|
|||
tdata = (pj_stun_tx_data*) pj_stun_client_tsx_get_data(tsx);
|
||||
sess = tdata->sess;
|
||||
|
||||
/* Lock the session and prevent user from destroying us in the callback */
|
||||
pj_atomic_inc(sess->busy);
|
||||
pj_lock_acquire(sess->lock);
|
||||
|
||||
/* Handle authentication challenge */
|
||||
handle_auth_challenge(sess, tdata, response, src_addr,
|
||||
src_addr_len, ¬ify_user);
|
||||
|
@ -387,6 +418,13 @@ static void stun_tsx_on_complete(pj_stun_client_tsx *tsx,
|
|||
*/
|
||||
pj_stun_msg_destroy_tdata(sess, tdata);
|
||||
tdata = NULL;
|
||||
|
||||
pj_lock_release(sess->lock);
|
||||
|
||||
if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) {
|
||||
pj_stun_session_destroy(sess);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static pj_status_t stun_tsx_on_send_msg(pj_stun_client_tsx *tsx,
|
||||
|
@ -394,12 +432,27 @@ static pj_status_t stun_tsx_on_send_msg(pj_stun_client_tsx *tsx,
|
|||
pj_size_t pkt_size)
|
||||
{
|
||||
pj_stun_tx_data *tdata;
|
||||
pj_stun_session *sess;
|
||||
pj_status_t status;
|
||||
|
||||
tdata = (pj_stun_tx_data*) pj_stun_client_tsx_get_data(tsx);
|
||||
sess = tdata->sess;
|
||||
|
||||
return tdata->sess->cb.on_send_msg(tdata->sess, tdata->token, stun_pkt,
|
||||
pkt_size, tdata->dst_addr,
|
||||
tdata->addr_len);
|
||||
/* Lock the session and prevent user from destroying us in the callback */
|
||||
pj_atomic_inc(sess->busy);
|
||||
pj_lock_acquire(sess->lock);
|
||||
|
||||
status = sess->cb.on_send_msg(tdata->sess, tdata->token, stun_pkt,
|
||||
pkt_size, tdata->dst_addr,
|
||||
tdata->addr_len);
|
||||
pj_lock_release(sess->lock);
|
||||
|
||||
if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) {
|
||||
pj_stun_session_destroy(sess);
|
||||
return PJNATH_ESTUNDESTROYED;
|
||||
} else {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
/* **************************************************************************/
|
||||
|
@ -428,11 +481,16 @@ PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_config *cfg,
|
|||
sess->pool = pool;
|
||||
pj_memcpy(&sess->cb, cb, sizeof(*cb));
|
||||
sess->use_fingerprint = fingerprint;
|
||||
sess->log_flag = 0xFFFF;
|
||||
|
||||
sess->srv_name.ptr = (char*) pj_pool_alloc(pool, 32);
|
||||
sess->srv_name.slen = pj_ansi_snprintf(sess->srv_name.ptr, 32,
|
||||
"pj_stun-%s", pj_get_version());
|
||||
|
||||
sess->rx_pool = pj_pool_create(sess->cfg->pf, "name",
|
||||
PJNATH_POOL_LEN_STUN_TDATA,
|
||||
PJNATH_POOL_INC_STUN_TDATA, NULL);
|
||||
|
||||
pj_list_init(&sess->pending_request_list);
|
||||
pj_list_init(&sess->cached_response_list);
|
||||
|
||||
|
@ -443,6 +501,13 @@ PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_config *cfg,
|
|||
}
|
||||
sess->delete_lock = PJ_TRUE;
|
||||
|
||||
status = pj_atomic_create(pool, 0, &sess->busy);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_lock_destroy(sess->lock);
|
||||
pj_pool_release(pool);
|
||||
return status;
|
||||
}
|
||||
|
||||
*p_sess = sess;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
|
@ -453,13 +518,22 @@ PJ_DEF(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess)
|
|||
PJ_ASSERT_RETURN(sess, PJ_EINVAL);
|
||||
|
||||
pj_lock_acquire(sess->lock);
|
||||
|
||||
/* Can't destroy if we're in a callback */
|
||||
sess->destroy_request = PJ_TRUE;
|
||||
if (pj_atomic_get(sess->busy)) {
|
||||
pj_lock_release(sess->lock);
|
||||
return PJ_EPENDING;
|
||||
}
|
||||
|
||||
while (!pj_list_empty(&sess->pending_request_list)) {
|
||||
pj_stun_tx_data *tdata = sess->pending_request_list.next;
|
||||
destroy_tdata(tdata);
|
||||
destroy_tdata(tdata, PJ_TRUE);
|
||||
}
|
||||
|
||||
while (!pj_list_empty(&sess->cached_response_list)) {
|
||||
pj_stun_tx_data *tdata = sess->cached_response_list.next;
|
||||
destroy_tdata(tdata);
|
||||
destroy_tdata(tdata, PJ_TRUE);
|
||||
}
|
||||
pj_lock_release(sess->lock);
|
||||
|
||||
|
@ -467,6 +541,11 @@ PJ_DEF(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess)
|
|||
pj_lock_destroy(sess->lock);
|
||||
}
|
||||
|
||||
if (sess->rx_pool) {
|
||||
pj_pool_release(sess->rx_pool);
|
||||
sess->rx_pool = NULL;
|
||||
}
|
||||
|
||||
pj_pool_release(sess->pool);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
|
@ -538,12 +617,19 @@ PJ_DEF(pj_status_t) pj_stun_session_set_credential(pj_stun_session *sess,
|
|||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
PJ_DEF(void) pj_stun_session_set_log( pj_stun_session *sess,
|
||||
unsigned flags)
|
||||
{
|
||||
PJ_ASSERT_ON_FAIL(sess, return);
|
||||
sess->log_flag = flags;
|
||||
}
|
||||
|
||||
static pj_status_t get_auth(pj_stun_session *sess,
|
||||
pj_stun_tx_data *tdata)
|
||||
{
|
||||
if (sess->cred.type == PJ_STUN_AUTH_CRED_STATIC) {
|
||||
tdata->auth_info.realm = sess->cred.data.static_cred.realm;
|
||||
//tdata->auth_info.realm = sess->cred.data.static_cred.realm;
|
||||
tdata->auth_info.realm = sess->server_realm;
|
||||
tdata->auth_info.username = sess->cred.data.static_cred.username;
|
||||
tdata->auth_info.nonce = sess->cred.data.static_cred.nonce;
|
||||
|
||||
|
@ -633,6 +719,7 @@ PJ_DEF(pj_status_t) pj_stun_session_create_req(pj_stun_session *sess,
|
|||
return status;
|
||||
}
|
||||
tdata->auth_info.nonce = sess->next_nonce;
|
||||
tdata->auth_info.realm = sess->server_realm;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -714,8 +801,18 @@ PJ_DEF(pj_status_t) pj_stun_session_create_res( pj_stun_session *sess,
|
|||
static void dump_tx_msg(pj_stun_session *sess, const pj_stun_msg *msg,
|
||||
unsigned pkt_size, const pj_sockaddr_t *addr)
|
||||
{
|
||||
char dst_name[80];
|
||||
char dst_name[PJ_INET6_ADDRSTRLEN+10];
|
||||
|
||||
if ((PJ_STUN_IS_REQUEST(msg->hdr.type) &&
|
||||
(sess->log_flag & PJ_STUN_SESS_LOG_TX_REQ)==0) ||
|
||||
(PJ_STUN_IS_RESPONSE(msg->hdr.type) &&
|
||||
(sess->log_flag & PJ_STUN_SESS_LOG_TX_RES)==0) ||
|
||||
(PJ_STUN_IS_INDICATION(msg->hdr.type) &&
|
||||
(sess->log_flag & PJ_STUN_SESS_LOG_TX_IND)==0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pj_sockaddr_print(addr, dst_name, sizeof(dst_name), 3);
|
||||
|
||||
PJ_LOG(5,(SNAME(sess),
|
||||
|
@ -749,7 +846,8 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
|
|||
tdata->token = token;
|
||||
tdata->retransmit = retransmit;
|
||||
|
||||
/* Start locking the session now */
|
||||
/* Lock the session and prevent user from destroying us in the callback */
|
||||
pj_atomic_inc(sess->busy);
|
||||
pj_lock_acquire(sess->lock);
|
||||
|
||||
/* Apply options */
|
||||
|
@ -757,9 +855,8 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
|
|||
tdata->msg);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_stun_msg_destroy_tdata(sess, tdata);
|
||||
pj_lock_release(sess->lock);
|
||||
LOG_ERR_(sess, "Error applying options", status);
|
||||
return status;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/* Encode message */
|
||||
|
@ -769,9 +866,8 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
|
|||
&tdata->pkt_size);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_stun_msg_destroy_tdata(sess, tdata);
|
||||
pj_lock_release(sess->lock);
|
||||
LOG_ERR_(sess, "STUN encode() error", status);
|
||||
return status;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/* Dump packet */
|
||||
|
@ -797,9 +893,8 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
|
|||
tdata->pkt, tdata->pkt_size);
|
||||
if (status != PJ_SUCCESS && status != PJ_EPENDING) {
|
||||
pj_stun_msg_destroy_tdata(sess, tdata);
|
||||
pj_lock_release(sess->lock);
|
||||
LOG_ERR_(sess, "Error sending STUN request", status);
|
||||
return status;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/* Add to pending request list */
|
||||
|
@ -824,10 +919,10 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
|
|||
&tdata->res_timer,
|
||||
&timeout);
|
||||
if (status != PJ_SUCCESS) {
|
||||
tdata->res_timer.id = PJ_FALSE;
|
||||
pj_stun_msg_destroy_tdata(sess, tdata);
|
||||
pj_lock_release(sess->lock);
|
||||
LOG_ERR_(sess, "Error scheduling response timer", status);
|
||||
return status;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
pj_list_push_back(&sess->cached_response_list, tdata);
|
||||
|
@ -838,7 +933,9 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
|
|||
tdata->pkt_size, server, addr_len);
|
||||
|
||||
if (status != PJ_SUCCESS && status != PJ_EPENDING) {
|
||||
pj_stun_msg_destroy_tdata(sess, tdata);
|
||||
LOG_ERR_(sess, "Error sending STUN request", status);
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/* Destroy only when response is not cached*/
|
||||
|
@ -847,8 +944,15 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
on_return:
|
||||
pj_lock_release(sess->lock);
|
||||
|
||||
/* Check if application has called destroy() in the callback */
|
||||
if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) {
|
||||
pj_stun_session_destroy(sess);
|
||||
return PJNATH_ESTUNDESTROYED;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -892,6 +996,8 @@ PJ_DEF(pj_status_t) pj_stun_session_cancel_req( pj_stun_session *sess,
|
|||
PJ_ASSERT_RETURN(!notify || notify_status!=PJ_SUCCESS, PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(PJ_STUN_IS_REQUEST(tdata->msg->hdr.type), PJ_EINVAL);
|
||||
|
||||
/* Lock the session and prevent user from destroying us in the callback */
|
||||
pj_atomic_inc(sess->busy);
|
||||
pj_lock_acquire(sess->lock);
|
||||
|
||||
if (notify) {
|
||||
|
@ -903,6 +1009,12 @@ PJ_DEF(pj_status_t) pj_stun_session_cancel_req( pj_stun_session *sess,
|
|||
pj_stun_msg_destroy_tdata(sess, tdata);
|
||||
|
||||
pj_lock_release(sess->lock);
|
||||
|
||||
if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) {
|
||||
pj_stun_session_destroy(sess);
|
||||
return PJNATH_ESTUNDESTROYED;
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -917,12 +1029,19 @@ PJ_DEF(pj_status_t) pj_stun_session_retransmit_req(pj_stun_session *sess,
|
|||
PJ_ASSERT_RETURN(sess && tdata, PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(PJ_STUN_IS_REQUEST(tdata->msg->hdr.type), PJ_EINVAL);
|
||||
|
||||
/* Lock the session and prevent user from destroying us in the callback */
|
||||
pj_atomic_inc(sess->busy);
|
||||
pj_lock_acquire(sess->lock);
|
||||
|
||||
status = pj_stun_client_tsx_retransmit(tdata->client_tsx);
|
||||
|
||||
pj_lock_release(sess->lock);
|
||||
|
||||
if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) {
|
||||
pj_stun_session_destroy(sess);
|
||||
return PJNATH_ESTUNDESTROYED;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -1165,6 +1284,36 @@ static pj_status_t on_incoming_indication(pj_stun_session *sess,
|
|||
}
|
||||
|
||||
|
||||
/* Print outgoing message to log */
|
||||
static void dump_rx_msg(pj_stun_session *sess, const pj_stun_msg *msg,
|
||||
unsigned pkt_size, const pj_sockaddr_t *addr)
|
||||
{
|
||||
char src_info[PJ_INET6_ADDRSTRLEN+10];
|
||||
|
||||
if ((PJ_STUN_IS_REQUEST(msg->hdr.type) &&
|
||||
(sess->log_flag & PJ_STUN_SESS_LOG_RX_REQ)==0) ||
|
||||
(PJ_STUN_IS_RESPONSE(msg->hdr.type) &&
|
||||
(sess->log_flag & PJ_STUN_SESS_LOG_RX_RES)==0) ||
|
||||
(PJ_STUN_IS_INDICATION(msg->hdr.type) &&
|
||||
(sess->log_flag & PJ_STUN_SESS_LOG_RX_IND)==0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pj_sockaddr_print(addr, src_info, sizeof(src_info), 3);
|
||||
|
||||
PJ_LOG(5,(SNAME(sess),
|
||||
"RX %d bytes STUN message from %s:\n"
|
||||
"--- begin STUN message ---\n"
|
||||
"%s"
|
||||
"--- end of STUN message ---\n",
|
||||
pkt_size, src_info,
|
||||
pj_stun_msg_dump(msg, sess->dump_buf, sizeof(sess->dump_buf),
|
||||
NULL)));
|
||||
|
||||
}
|
||||
|
||||
/* Incoming packet */
|
||||
PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
|
||||
const void *packet,
|
||||
pj_size_t pkt_size,
|
||||
|
@ -1175,47 +1324,34 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
|
|||
unsigned src_addr_len)
|
||||
{
|
||||
pj_stun_msg *msg, *response;
|
||||
pj_pool_t *tmp_pool;
|
||||
char *dump;
|
||||
pj_status_t status;
|
||||
|
||||
PJ_ASSERT_RETURN(sess && packet && pkt_size, PJ_EINVAL);
|
||||
|
||||
tmp_pool = pj_pool_create(sess->cfg->pf, "tmpstun",
|
||||
PJNATH_POOL_LEN_STUN_TDATA,
|
||||
PJNATH_POOL_INC_STUN_TDATA, NULL);
|
||||
if (!tmp_pool)
|
||||
return PJ_ENOMEM;
|
||||
/* Lock the session and prevent user from destroying us in the callback */
|
||||
pj_atomic_inc(sess->busy);
|
||||
pj_lock_acquire(sess->lock);
|
||||
|
||||
/* Reset pool */
|
||||
pj_pool_reset(sess->rx_pool);
|
||||
|
||||
/* Try to parse the message */
|
||||
status = pj_stun_msg_decode(tmp_pool, (const pj_uint8_t*)packet,
|
||||
status = pj_stun_msg_decode(sess->rx_pool, (const pj_uint8_t*)packet,
|
||||
pkt_size, options,
|
||||
&msg, parsed_len, &response);
|
||||
if (status != PJ_SUCCESS) {
|
||||
LOG_ERR_(sess, "STUN msg_decode() error", status);
|
||||
if (response) {
|
||||
send_response(sess, token, tmp_pool, response, NULL,
|
||||
send_response(sess, token, sess->rx_pool, response, NULL,
|
||||
PJ_FALSE, src_addr, src_addr_len);
|
||||
}
|
||||
pj_pool_release(tmp_pool);
|
||||
return status;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
dump = (char*) pj_pool_alloc(tmp_pool, PJ_STUN_MAX_PKT_LEN);
|
||||
|
||||
PJ_LOG(5,(SNAME(sess),
|
||||
"RX STUN message from %s:%d:\n"
|
||||
"--- begin STUN message ---\n"
|
||||
"%s"
|
||||
"--- end of STUN message ---\n",
|
||||
pj_inet_ntoa(((pj_sockaddr_in*)src_addr)->sin_addr),
|
||||
pj_ntohs(((pj_sockaddr_in*)src_addr)->sin_port),
|
||||
pj_stun_msg_dump(msg, dump, PJ_STUN_MAX_PKT_LEN, NULL)));
|
||||
|
||||
pj_lock_acquire(sess->lock);
|
||||
dump_rx_msg(sess, msg, pkt_size, src_addr);
|
||||
|
||||
/* For requests, check if we have cached response */
|
||||
status = check_cached_response(sess, tmp_pool, msg,
|
||||
status = check_cached_response(sess, sess->rx_pool, msg,
|
||||
src_addr, src_addr_len);
|
||||
if (status == PJ_SUCCESS) {
|
||||
goto on_return;
|
||||
|
@ -1231,13 +1367,13 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
|
|||
|
||||
} else if (PJ_STUN_IS_REQUEST(msg->hdr.type)) {
|
||||
|
||||
status = on_incoming_request(sess, options, token, tmp_pool,
|
||||
status = on_incoming_request(sess, options, token, sess->rx_pool,
|
||||
(const pj_uint8_t*) packet, pkt_size,
|
||||
msg, src_addr, src_addr_len);
|
||||
|
||||
} else if (PJ_STUN_IS_INDICATION(msg->hdr.type)) {
|
||||
|
||||
status = on_incoming_indication(sess, token, tmp_pool,
|
||||
status = on_incoming_indication(sess, token, sess->rx_pool,
|
||||
(const pj_uint8_t*) packet, pkt_size,
|
||||
msg, src_addr, src_addr_len);
|
||||
|
||||
|
@ -1249,9 +1385,14 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
|
|||
on_return:
|
||||
pj_lock_release(sess->lock);
|
||||
|
||||
pj_pool_release(tmp_pool);
|
||||
/* If we've received destroy request while we're on the callback,
|
||||
* destroy the session now.
|
||||
*/
|
||||
if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) {
|
||||
pj_stun_session_destroy(sess);
|
||||
return PJNATH_ESTUNDESTROYED;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,829 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
* Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <pjnath/stun_sock.h>
|
||||
#include <pjnath/errno.h>
|
||||
#include <pjnath/stun_transaction.h>
|
||||
#include <pjnath/stun_session.h>
|
||||
#include <pjlib-util/srv_resolver.h>
|
||||
#include <pj/activesock.h>
|
||||
#include <pj/addr_resolv.h>
|
||||
#include <pj/array.h>
|
||||
#include <pj/assert.h>
|
||||
#include <pj/ip_helper.h>
|
||||
#include <pj/log.h>
|
||||
#include <pj/pool.h>
|
||||
#include <pj/rand.h>
|
||||
|
||||
|
||||
struct pj_stun_sock
|
||||
{
|
||||
char *obj_name; /* Log identification */
|
||||
pj_pool_t *pool; /* Pool */
|
||||
void *user_data; /* Application user data */
|
||||
|
||||
int af; /* Address family */
|
||||
pj_stun_config stun_cfg; /* STUN config (ioqueue etc)*/
|
||||
pj_stun_sock_cb cb; /* Application callbacks */
|
||||
|
||||
int ka_interval; /* Keep alive interval */
|
||||
pj_timer_entry ka_timer; /* Keep alive timer. */
|
||||
|
||||
pj_sockaddr srv_addr; /* Resolved server addr */
|
||||
pj_sockaddr mapped_addr; /* Our public address */
|
||||
|
||||
pj_dns_async_query *q; /* Pending DNS query */
|
||||
pj_sock_t sock_fd; /* Socket descriptor */
|
||||
pj_activesock_t *active_sock; /* Active socket object */
|
||||
pj_ioqueue_op_key_t send_key; /* Default send key for app */
|
||||
pj_ioqueue_op_key_t int_send_key; /* Send key for internal */
|
||||
|
||||
pj_uint16_t tsx_id[6]; /* .. to match STUN msg */
|
||||
pj_stun_session *stun_sess; /* STUN session */
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Prototypes for static functions
|
||||
*/
|
||||
|
||||
/* This callback is called by the STUN session to send packet */
|
||||
static pj_status_t sess_on_send_msg(pj_stun_session *sess,
|
||||
void *token,
|
||||
const void *pkt,
|
||||
pj_size_t pkt_size,
|
||||
const pj_sockaddr_t *dst_addr,
|
||||
unsigned addr_len);
|
||||
|
||||
/* This callback is called by the STUN session when outgoing transaction
|
||||
* is complete
|
||||
*/
|
||||
static void sess_on_request_complete(pj_stun_session *sess,
|
||||
pj_status_t status,
|
||||
void *token,
|
||||
pj_stun_tx_data *tdata,
|
||||
const pj_stun_msg *response,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len);
|
||||
/* DNS resolver callback */
|
||||
static void dns_srv_resolver_cb(void *user_data,
|
||||
pj_status_t status,
|
||||
const pj_dns_srv_record *rec);
|
||||
|
||||
/* Start sending STUN Binding request */
|
||||
static pj_status_t get_mapped_addr(pj_stun_sock *stun_sock);
|
||||
|
||||
/* Callback from active socket when incoming packet is received */
|
||||
static pj_bool_t on_data_recvfrom(pj_activesock_t *asock,
|
||||
void *data,
|
||||
pj_size_t size,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
int addr_len,
|
||||
pj_status_t status);
|
||||
|
||||
/* Callback from active socket about send status */
|
||||
static pj_bool_t on_data_sent(pj_activesock_t *asock,
|
||||
pj_ioqueue_op_key_t *send_key,
|
||||
pj_ssize_t sent);
|
||||
|
||||
/* Schedule keep-alive timer */
|
||||
static void start_ka_timer(pj_stun_sock *stun_sock);
|
||||
|
||||
/* Keep-alive timer callback */
|
||||
static void ka_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te);
|
||||
|
||||
#define INTERNAL_MSG_TOKEN (void*)1
|
||||
|
||||
|
||||
/*
|
||||
* Retrieve the name representing the specified operation.
|
||||
*/
|
||||
PJ_DEF(const char*) pj_stun_sock_op_name(pj_stun_sock_op op)
|
||||
{
|
||||
const char *names[] = {
|
||||
"?",
|
||||
"DNS resolution",
|
||||
"STUN Binding request",
|
||||
"Keep-alive"
|
||||
};
|
||||
|
||||
return op <= PJ_STUN_SOCK_KEEP_ALIVE_OP ? names[op] : "?";
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Initialize the STUN transport setting with its default values.
|
||||
*/
|
||||
PJ_DEF(void) pj_stun_sock_cfg_default(pj_stun_sock_cfg *cfg)
|
||||
{
|
||||
pj_bzero(cfg, sizeof(*cfg));
|
||||
cfg->max_pkt_size = PJ_STUN_SOCK_PKT_LEN;
|
||||
cfg->async_cnt = 1;
|
||||
cfg->ka_interval = PJ_STUN_KEEP_ALIVE_SEC;
|
||||
}
|
||||
|
||||
|
||||
/* Check that configuration setting is valid */
|
||||
static pj_bool_t pj_stun_sock_cfg_is_valid(const pj_stun_sock_cfg *cfg)
|
||||
{
|
||||
return cfg->max_pkt_size > 1 && cfg->async_cnt >= 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the STUN transport using the specified configuration.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg,
|
||||
const char *name,
|
||||
int af,
|
||||
const pj_stun_sock_cb *cb,
|
||||
const pj_stun_sock_cfg *cfg,
|
||||
void *user_data,
|
||||
pj_stun_sock **p_stun_sock)
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
pj_stun_sock *stun_sock;
|
||||
pj_stun_sock_cfg default_cfg;
|
||||
unsigned i;
|
||||
pj_status_t status;
|
||||
|
||||
PJ_ASSERT_RETURN(stun_cfg && cb && p_stun_sock, PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(af==pj_AF_INET()||af==pj_AF_INET6(), PJ_EAFNOTSUP);
|
||||
PJ_ASSERT_RETURN(!cfg || pj_stun_sock_cfg_is_valid(cfg), PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(cb->on_status, PJ_EINVAL);
|
||||
|
||||
status = pj_stun_config_check_valid(stun_cfg);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (name == NULL)
|
||||
name = "stuntp%p";
|
||||
|
||||
if (cfg == NULL) {
|
||||
pj_stun_sock_cfg_default(&default_cfg);
|
||||
cfg = &default_cfg;
|
||||
}
|
||||
|
||||
|
||||
/* Create structure */
|
||||
pool = pj_pool_create(stun_cfg->pf, name, 256, 512, NULL);
|
||||
stun_sock = PJ_POOL_ZALLOC_T(pool, pj_stun_sock);
|
||||
stun_sock->pool = pool;
|
||||
stun_sock->obj_name = pool->obj_name;
|
||||
stun_sock->user_data = user_data;
|
||||
stun_sock->af = af;
|
||||
stun_sock->sock_fd = PJ_INVALID_SOCKET;
|
||||
pj_memcpy(&stun_sock->stun_cfg, stun_cfg, sizeof(*stun_cfg));
|
||||
pj_memcpy(&stun_sock->cb, cb, sizeof(*cb));
|
||||
|
||||
stun_sock->ka_interval = cfg->ka_interval;
|
||||
if (stun_sock->ka_interval == 0)
|
||||
stun_sock->ka_interval = PJ_STUN_KEEP_ALIVE_SEC;
|
||||
|
||||
/* Create socket and bind socket */
|
||||
status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &stun_sock->sock_fd);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
if (pj_sockaddr_has_addr(&cfg->bound_addr)) {
|
||||
status = pj_sock_bind(stun_sock->sock_fd, &cfg->bound_addr,
|
||||
pj_sockaddr_get_len(&cfg->bound_addr));
|
||||
} else {
|
||||
pj_sockaddr bound_addr;
|
||||
|
||||
pj_sockaddr_init(af, &bound_addr, NULL, 0);
|
||||
status = pj_sock_bind(stun_sock->sock_fd, &bound_addr,
|
||||
pj_sockaddr_get_len(&bound_addr));
|
||||
}
|
||||
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
/* Create more useful information string about this transport */
|
||||
#if 0
|
||||
{
|
||||
pj_sockaddr bound_addr;
|
||||
int addr_len = sizeof(bound_addr);
|
||||
|
||||
status = pj_sock_getsockname(stun_sock->sock_fd, &bound_addr,
|
||||
&addr_len);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
stun_sock->info = pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN+10);
|
||||
pj_sockaddr_print(&bound_addr, stun_sock->info,
|
||||
PJ_INET6_ADDRSTRLEN, 3);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Init active socket configuration */
|
||||
{
|
||||
pj_activesock_cfg activesock_cfg;
|
||||
pj_activesock_cb activesock_cb;
|
||||
|
||||
pj_activesock_cfg_default(&activesock_cfg);
|
||||
activesock_cfg.async_cnt = cfg->async_cnt;
|
||||
activesock_cfg.concurrency = 0;
|
||||
|
||||
/* Create the active socket */
|
||||
pj_bzero(&activesock_cb, sizeof(activesock_cb));
|
||||
activesock_cb.on_data_recvfrom = &on_data_recvfrom;
|
||||
activesock_cb.on_data_sent = &on_data_sent;
|
||||
status = pj_activesock_create(pool, stun_sock->sock_fd,
|
||||
pj_SOCK_DGRAM(),
|
||||
&activesock_cfg, stun_cfg->ioqueue,
|
||||
&activesock_cb, stun_sock,
|
||||
&stun_sock->active_sock);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
/* Start asynchronous read operations */
|
||||
status = pj_activesock_start_recvfrom(stun_sock->active_sock, pool,
|
||||
cfg->max_pkt_size, 0);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
/* Init send keys */
|
||||
pj_ioqueue_op_key_init(&stun_sock->send_key,
|
||||
sizeof(stun_sock->send_key));
|
||||
pj_ioqueue_op_key_init(&stun_sock->int_send_key,
|
||||
sizeof(stun_sock->int_send_key));
|
||||
}
|
||||
|
||||
/* Create STUN session */
|
||||
{
|
||||
pj_stun_session_cb sess_cb;
|
||||
|
||||
pj_bzero(&sess_cb, sizeof(sess_cb));
|
||||
sess_cb.on_request_complete = &sess_on_request_complete;
|
||||
sess_cb.on_send_msg = &sess_on_send_msg;
|
||||
status = pj_stun_session_create(&stun_sock->stun_cfg,
|
||||
stun_sock->obj_name,
|
||||
&sess_cb, PJ_FALSE,
|
||||
&stun_sock->stun_sess);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
/* Associate us with the STUN session */
|
||||
pj_stun_session_set_user_data(stun_sock->stun_sess, stun_sock);
|
||||
|
||||
/* Initialize random numbers to be used as STUN transaction ID for
|
||||
* outgoing Binding request. We use the 80bit number to distinguish
|
||||
* STUN messages we sent with STUN messages that the application sends.
|
||||
* The last 16bit value in the array is a counter.
|
||||
*/
|
||||
for (i=0; i<PJ_ARRAY_SIZE(stun_sock->tsx_id); ++i) {
|
||||
stun_sock->tsx_id[i] = (pj_uint16_t) pj_rand();
|
||||
}
|
||||
stun_sock->tsx_id[5] = 0;
|
||||
|
||||
|
||||
/* Init timer entry */
|
||||
stun_sock->ka_timer.cb = &ka_timer_cb;
|
||||
stun_sock->ka_timer.user_data = stun_sock;
|
||||
|
||||
/* Done */
|
||||
*p_stun_sock = stun_sock;
|
||||
return PJ_SUCCESS;
|
||||
|
||||
on_error:
|
||||
pj_stun_sock_destroy(stun_sock);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Start socket. */
|
||||
PJ_DEF(pj_status_t) pj_stun_sock_start( pj_stun_sock *stun_sock,
|
||||
const pj_str_t *domain,
|
||||
pj_uint16_t default_port,
|
||||
pj_dns_resolver *resolver)
|
||||
{
|
||||
pj_status_t status;
|
||||
|
||||
PJ_ASSERT_RETURN(stun_sock && domain && default_port, PJ_EINVAL);
|
||||
|
||||
/* Check whether the domain contains IP address */
|
||||
stun_sock->srv_addr.addr.sa_family = (pj_uint16_t)stun_sock->af;
|
||||
status = pj_inet_pton(stun_sock->af, domain,
|
||||
pj_sockaddr_get_addr(&stun_sock->srv_addr));
|
||||
if (status != PJ_SUCCESS) {
|
||||
stun_sock->srv_addr.addr.sa_family = (pj_uint16_t)0;
|
||||
}
|
||||
|
||||
/* If resolver is set, try to resolve with DNS SRV first. It
|
||||
* will fallback to DNS A/AAAA when no SRV record is found.
|
||||
*/
|
||||
if (status != PJ_SUCCESS && resolver) {
|
||||
const pj_str_t res_name = pj_str("_stun._udp.");
|
||||
unsigned opt;
|
||||
|
||||
pj_assert(stun_sock->q == NULL);
|
||||
|
||||
opt = PJ_DNS_SRV_FALLBACK_A;
|
||||
if (stun_sock->af == pj_AF_INET6()) {
|
||||
opt |= (PJ_DNS_SRV_RESOLVE_AAAA | PJ_DNS_SRV_FALLBACK_AAAA);
|
||||
}
|
||||
|
||||
status = pj_dns_srv_resolve(domain, &res_name, default_port,
|
||||
stun_sock->pool, resolver, opt,
|
||||
stun_sock, &dns_srv_resolver_cb,
|
||||
&stun_sock->q);
|
||||
|
||||
/* Processing will resume when the DNS SRV callback is called */
|
||||
return status;
|
||||
|
||||
} else {
|
||||
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_addrinfo ai;
|
||||
unsigned cnt = 1;
|
||||
|
||||
status = pj_getaddrinfo(stun_sock->af, domain, &cnt, &ai);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
pj_sockaddr_cp(&stun_sock->srv_addr, &ai.ai_addr);
|
||||
}
|
||||
|
||||
pj_sockaddr_set_port(&stun_sock->srv_addr, (pj_uint16_t)default_port);
|
||||
|
||||
/* Start sending Binding request */
|
||||
return get_mapped_addr(stun_sock);
|
||||
}
|
||||
}
|
||||
|
||||
/* Destroy */
|
||||
PJ_DEF(pj_status_t) pj_stun_sock_destroy(pj_stun_sock *stun_sock)
|
||||
{
|
||||
if (stun_sock->q) {
|
||||
pj_dns_resolver_cancel_query(stun_sock->q, PJ_FALSE);
|
||||
stun_sock->q = NULL;
|
||||
}
|
||||
|
||||
/* Destroy the active socket first just in case we'll get
|
||||
* stray callback.
|
||||
*/
|
||||
if (stun_sock->active_sock != NULL) {
|
||||
pj_activesock_close(stun_sock->active_sock);
|
||||
stun_sock->active_sock = NULL;
|
||||
stun_sock->sock_fd = PJ_INVALID_SOCKET;
|
||||
} else if (stun_sock->sock_fd != PJ_INVALID_SOCKET) {
|
||||
pj_sock_close(stun_sock->sock_fd);
|
||||
stun_sock->sock_fd = PJ_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (stun_sock->ka_timer.id != 0) {
|
||||
pj_timer_heap_cancel(stun_sock->stun_cfg.timer_heap,
|
||||
&stun_sock->ka_timer);
|
||||
stun_sock->ka_timer.id = 0;
|
||||
}
|
||||
|
||||
if (stun_sock->stun_sess) {
|
||||
pj_stun_session_destroy(stun_sock->stun_sess);
|
||||
stun_sock->stun_sess = NULL;
|
||||
}
|
||||
|
||||
if (stun_sock->pool) {
|
||||
pj_pool_t *pool = stun_sock->pool;
|
||||
stun_sock->pool = NULL;
|
||||
pj_pool_release(pool);
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* Associate user data */
|
||||
PJ_DEF(pj_status_t) pj_stun_sock_set_user_data( pj_stun_sock *stun_sock,
|
||||
void *user_data)
|
||||
{
|
||||
PJ_ASSERT_RETURN(stun_sock, PJ_EINVAL);
|
||||
stun_sock->user_data = user_data;
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Get user data */
|
||||
PJ_DEF(void*) pj_stun_sock_get_user_data(pj_stun_sock *stun_sock)
|
||||
{
|
||||
PJ_ASSERT_RETURN(stun_sock, NULL);
|
||||
return stun_sock->user_data;
|
||||
}
|
||||
|
||||
/* Notify application that session has failed */
|
||||
static pj_bool_t sess_fail(pj_stun_sock *stun_sock,
|
||||
pj_stun_sock_op op,
|
||||
pj_status_t status)
|
||||
{
|
||||
char errmsg[PJ_ERR_MSG_SIZE];
|
||||
pj_bool_t ret;
|
||||
|
||||
pj_strerror(status, errmsg, sizeof(errmsg));
|
||||
PJ_LOG(4,(stun_sock->obj_name, "Session failed because %s failed: %s",
|
||||
pj_stun_sock_op_name(op), errmsg));
|
||||
|
||||
ret = (*stun_sock->cb.on_status)(stun_sock, op, status);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* DNS resolver callback */
|
||||
static void dns_srv_resolver_cb(void *user_data,
|
||||
pj_status_t status,
|
||||
const pj_dns_srv_record *rec)
|
||||
{
|
||||
pj_stun_sock *stun_sock = (pj_stun_sock*) user_data;
|
||||
|
||||
/* Clear query */
|
||||
stun_sock->q = NULL;
|
||||
|
||||
/* Handle error */
|
||||
if (status != PJ_SUCCESS) {
|
||||
sess_fail(stun_sock, PJ_STUN_SOCK_DNS_OP, status);
|
||||
return;
|
||||
}
|
||||
|
||||
pj_assert(rec->count);
|
||||
pj_assert(rec->entry[0].server.addr_count);
|
||||
|
||||
PJ_TODO(SUPPORT_IPV6_IN_RESOLVER);
|
||||
pj_assert(stun_sock->af == pj_AF_INET());
|
||||
|
||||
/* Set the address */
|
||||
pj_sockaddr_in_init(&stun_sock->srv_addr.ipv4, NULL,
|
||||
rec->entry[0].port);
|
||||
stun_sock->srv_addr.ipv4.sin_addr = rec->entry[0].server.addr[0];
|
||||
|
||||
/* Start sending Binding request */
|
||||
get_mapped_addr(stun_sock);
|
||||
}
|
||||
|
||||
|
||||
/* Start sending STUN Binding request */
|
||||
static pj_status_t get_mapped_addr(pj_stun_sock *stun_sock)
|
||||
{
|
||||
pj_stun_tx_data *tdata;
|
||||
pj_status_t status;
|
||||
|
||||
/* Increment request counter and create STUN Binding request */
|
||||
++stun_sock->tsx_id[5];
|
||||
status = pj_stun_session_create_req(stun_sock->stun_sess,
|
||||
PJ_STUN_BINDING_REQUEST,
|
||||
PJ_STUN_MAGIC,
|
||||
(const pj_uint8_t*)stun_sock->tsx_id,
|
||||
&tdata);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
/* Send request */
|
||||
status=pj_stun_session_send_msg(stun_sock->stun_sess, INTERNAL_MSG_TOKEN,
|
||||
PJ_FALSE, PJ_TRUE, &stun_sock->srv_addr,
|
||||
pj_sockaddr_get_len(&stun_sock->srv_addr),
|
||||
tdata);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
|
||||
on_error:
|
||||
sess_fail(stun_sock, PJ_STUN_SOCK_BINDING_OP, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Get info */
|
||||
PJ_DEF(pj_status_t) pj_stun_sock_get_info( pj_stun_sock *stun_sock,
|
||||
pj_stun_sock_info *info)
|
||||
{
|
||||
int addr_len;
|
||||
pj_status_t status;
|
||||
|
||||
PJ_ASSERT_RETURN(stun_sock && info, PJ_EINVAL);
|
||||
|
||||
/* Copy STUN server address and mapped address */
|
||||
pj_memcpy(&info->srv_addr, &stun_sock->srv_addr,
|
||||
sizeof(pj_sockaddr));
|
||||
pj_memcpy(&info->mapped_addr, &stun_sock->mapped_addr,
|
||||
sizeof(pj_sockaddr));
|
||||
|
||||
/* Retrieve bound address */
|
||||
addr_len = sizeof(info->bound_addr);
|
||||
status = pj_sock_getsockname(stun_sock->sock_fd, &info->bound_addr,
|
||||
&addr_len);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* If socket is bound to a specific interface, then only put that
|
||||
* interface in the alias list. Otherwise query all the interfaces
|
||||
* in the host.
|
||||
*/
|
||||
if (pj_sockaddr_has_addr(&info->bound_addr)) {
|
||||
info->alias_cnt = 1;
|
||||
pj_sockaddr_cp(&info->aliases[0], &info->bound_addr);
|
||||
} else {
|
||||
unsigned i;
|
||||
|
||||
/* Enum all IP interfaces in the host */
|
||||
info->alias_cnt = PJ_ARRAY_SIZE(info->aliases);
|
||||
status = pj_enum_ip_interface(stun_sock->af, &info->alias_cnt,
|
||||
info->aliases);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Set the port number for each address.
|
||||
*/
|
||||
if (stun_sock->af == pj_AF_INET()) {
|
||||
for (i=0; i<info->alias_cnt; ++i) {
|
||||
pj_sockaddr_set_port(&info->aliases[i],
|
||||
pj_sockaddr_get_port(&info->bound_addr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* Send application data */
|
||||
PJ_DEF(pj_status_t) pj_stun_sock_sendto( pj_stun_sock *stun_sock,
|
||||
pj_ioqueue_op_key_t *send_key,
|
||||
const void *pkt,
|
||||
unsigned pkt_len,
|
||||
unsigned flag,
|
||||
const pj_sockaddr_t *dst_addr,
|
||||
unsigned addr_len)
|
||||
{
|
||||
pj_ssize_t size;
|
||||
PJ_ASSERT_RETURN(stun_sock && pkt && dst_addr && addr_len, PJ_EINVAL);
|
||||
|
||||
if (send_key==NULL)
|
||||
send_key = &stun_sock->send_key;
|
||||
|
||||
size = pkt_len;
|
||||
return pj_activesock_sendto(stun_sock->active_sock, send_key,
|
||||
pkt, &size, flag, dst_addr, addr_len);
|
||||
}
|
||||
|
||||
/* This callback is called by the STUN session to send packet */
|
||||
static pj_status_t sess_on_send_msg(pj_stun_session *sess,
|
||||
void *token,
|
||||
const void *pkt,
|
||||
pj_size_t pkt_size,
|
||||
const pj_sockaddr_t *dst_addr,
|
||||
unsigned addr_len)
|
||||
{
|
||||
pj_stun_sock *stun_sock;
|
||||
pj_ssize_t size;
|
||||
|
||||
stun_sock = (pj_stun_sock *) pj_stun_session_get_user_data(sess);
|
||||
|
||||
pj_assert(token==INTERNAL_MSG_TOKEN);
|
||||
PJ_UNUSED_ARG(token);
|
||||
|
||||
size = pkt_size;
|
||||
return pj_activesock_sendto(stun_sock->active_sock,
|
||||
&stun_sock->int_send_key,
|
||||
pkt, &size, 0, dst_addr, addr_len);
|
||||
}
|
||||
|
||||
/* This callback is called by the STUN session when outgoing transaction
|
||||
* is complete
|
||||
*/
|
||||
static void sess_on_request_complete(pj_stun_session *sess,
|
||||
pj_status_t status,
|
||||
void *token,
|
||||
pj_stun_tx_data *tdata,
|
||||
const pj_stun_msg *response,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len)
|
||||
{
|
||||
pj_stun_sock *stun_sock;
|
||||
const pj_stun_sockaddr_attr *mapped_attr;
|
||||
pj_stun_sock_op op;
|
||||
pj_bool_t mapped_changed;
|
||||
pj_bool_t resched = PJ_TRUE;
|
||||
|
||||
stun_sock = (pj_stun_sock *) pj_stun_session_get_user_data(sess);
|
||||
|
||||
PJ_UNUSED_ARG(tdata);
|
||||
PJ_UNUSED_ARG(token);
|
||||
PJ_UNUSED_ARG(src_addr);
|
||||
PJ_UNUSED_ARG(src_addr_len);
|
||||
|
||||
/* Check if this is a keep-alive or the first Binding request */
|
||||
if (pj_sockaddr_has_addr(&stun_sock->mapped_addr))
|
||||
op = PJ_STUN_SOCK_KEEP_ALIVE_OP;
|
||||
else
|
||||
op = PJ_STUN_SOCK_BINDING_OP;
|
||||
|
||||
/* Handle failure */
|
||||
if (status != PJ_SUCCESS) {
|
||||
resched = sess_fail(stun_sock, op, status);
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/* Get XOR-MAPPED-ADDRESS, or MAPPED-ADDRESS when XOR-MAPPED-ADDRESS
|
||||
* doesn't exist.
|
||||
*/
|
||||
mapped_attr = (const pj_stun_sockaddr_attr*)
|
||||
pj_stun_msg_find_attr(response, PJ_STUN_ATTR_XOR_MAPPED_ADDR,
|
||||
0);
|
||||
if (mapped_attr==NULL) {
|
||||
mapped_attr = (const pj_stun_sockaddr_attr*)
|
||||
pj_stun_msg_find_attr(response, PJ_STUN_ATTR_MAPPED_ADDR,
|
||||
0);
|
||||
}
|
||||
|
||||
if (mapped_attr == NULL) {
|
||||
resched = sess_fail(stun_sock, op, PJNATH_ESTUNNOMAPPEDADDR);
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/* Determine if mapped address has changed, and save the new mapped
|
||||
* address and call callback if so
|
||||
*/
|
||||
mapped_changed = !pj_sockaddr_has_addr(&stun_sock->mapped_addr) ||
|
||||
pj_sockaddr_cmp(&stun_sock->mapped_addr,
|
||||
&mapped_attr->sockaddr) != 0;
|
||||
if (mapped_changed) {
|
||||
/* Print mapped adress */
|
||||
{
|
||||
char addrinfo[PJ_INET6_ADDRSTRLEN+10];
|
||||
PJ_LOG(4,(stun_sock->obj_name,
|
||||
"STUN mapped address found/changed: %s",
|
||||
pj_sockaddr_print(&mapped_attr->sockaddr,
|
||||
addrinfo, sizeof(addrinfo), 3)));
|
||||
}
|
||||
|
||||
pj_sockaddr_cp(&stun_sock->mapped_addr, &mapped_attr->sockaddr);
|
||||
|
||||
resched = (*stun_sock->cb.on_status)(stun_sock, op, PJ_SUCCESS);
|
||||
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
on_return:
|
||||
/* Start/restart keep-alive timer */
|
||||
if (resched)
|
||||
start_ka_timer(stun_sock);
|
||||
}
|
||||
|
||||
/* Schedule keep-alive timer */
|
||||
static void start_ka_timer(pj_stun_sock *stun_sock)
|
||||
{
|
||||
if (stun_sock->ka_timer.id != 0) {
|
||||
pj_timer_heap_cancel(stun_sock->stun_cfg.timer_heap,
|
||||
&stun_sock->ka_timer);
|
||||
stun_sock->ka_timer.id = 0;
|
||||
}
|
||||
|
||||
pj_assert(stun_sock->ka_interval != 0);
|
||||
if (stun_sock->ka_interval > 0) {
|
||||
pj_time_val delay;
|
||||
|
||||
delay.sec = stun_sock->ka_interval;
|
||||
delay.msec = 0;
|
||||
|
||||
if (pj_timer_heap_schedule(stun_sock->stun_cfg.timer_heap,
|
||||
&stun_sock->ka_timer,
|
||||
&delay) == PJ_SUCCESS)
|
||||
{
|
||||
stun_sock->ka_timer.id = PJ_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Keep-alive timer callback */
|
||||
static void ka_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te)
|
||||
{
|
||||
pj_stun_sock *stun_sock;
|
||||
|
||||
stun_sock = (pj_stun_sock *) te->user_data;
|
||||
|
||||
PJ_UNUSED_ARG(th);
|
||||
|
||||
/* Time to send STUN Binding request */
|
||||
if (get_mapped_addr(stun_sock) != PJ_SUCCESS)
|
||||
return;
|
||||
|
||||
/* Next keep-alive timer will be scheduled once the request
|
||||
* is complete.
|
||||
*/
|
||||
}
|
||||
|
||||
/* Callback from active socket when incoming packet is received */
|
||||
static pj_bool_t on_data_recvfrom(pj_activesock_t *asock,
|
||||
void *data,
|
||||
pj_size_t size,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
int addr_len,
|
||||
pj_status_t status)
|
||||
{
|
||||
pj_stun_sock *stun_sock;
|
||||
pj_stun_msg_hdr *hdr;
|
||||
pj_uint16_t type;
|
||||
|
||||
stun_sock = (pj_stun_sock*) pj_activesock_get_user_data(asock);
|
||||
|
||||
/* Log socket error */
|
||||
if (status != PJ_SUCCESS) {
|
||||
char errmsg[PJ_ERR_MSG_SIZE];
|
||||
|
||||
pj_strerror(status, errmsg, sizeof(errmsg));
|
||||
PJ_LOG(4,(stun_sock->obj_name, "recvfrom() error: %s", errmsg));
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
/* Check that this is STUN message */
|
||||
status = pj_stun_msg_check((const pj_uint8_t*)data, size,
|
||||
PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET);
|
||||
if (status != PJ_SUCCESS) {
|
||||
/* Not STUN -- give it to application */
|
||||
goto process_app_data;
|
||||
}
|
||||
|
||||
/* Treat packet as STUN header and copy the STUN message type.
|
||||
* We don't want to access the type directly from the header
|
||||
* since it may not be properly aligned.
|
||||
*/
|
||||
hdr = (pj_stun_msg_hdr*) data;
|
||||
pj_memcpy(&type, &hdr->type, 2);
|
||||
type = pj_ntohs(type);
|
||||
|
||||
/* If the packet is a STUN Binding response and part of the
|
||||
* transaction ID matches our internal ID, then this is
|
||||
* our internal STUN message (Binding request or keep alive).
|
||||
* Give it to our STUN session.
|
||||
*/
|
||||
if (!PJ_STUN_IS_RESPONSE(type) ||
|
||||
PJ_STUN_GET_METHOD(type) != PJ_STUN_BINDING_METHOD ||
|
||||
pj_memcmp(hdr->tsx_id, stun_sock->tsx_id, 10) != 0)
|
||||
{
|
||||
/* Not STUN Binding response, or STUN transaction ID mismatch.
|
||||
* This is not our message too -- give it to application.
|
||||
*/
|
||||
goto process_app_data;
|
||||
}
|
||||
|
||||
/* This is our STUN Binding response. Give it to the STUN session */
|
||||
status = pj_stun_session_on_rx_pkt(stun_sock->stun_sess, data, size,
|
||||
PJ_STUN_IS_DATAGRAM, NULL, NULL,
|
||||
src_addr, addr_len);
|
||||
return status!=PJNATH_ESTUNDESTROYED ? PJ_TRUE : PJ_FALSE;
|
||||
|
||||
process_app_data:
|
||||
if (stun_sock->cb.on_rx_data) {
|
||||
pj_bool_t ret;
|
||||
|
||||
ret = (*stun_sock->cb.on_rx_data)(stun_sock, data, size,
|
||||
src_addr, addr_len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
/* Callback from active socket about send status */
|
||||
static pj_bool_t on_data_sent(pj_activesock_t *asock,
|
||||
pj_ioqueue_op_key_t *send_key,
|
||||
pj_ssize_t sent)
|
||||
{
|
||||
pj_stun_sock *stun_sock;
|
||||
|
||||
stun_sock = (pj_stun_sock*) pj_activesock_get_user_data(asock);
|
||||
|
||||
/* Don't report to callback if this is internal message */
|
||||
if (send_key == &stun_sock->int_send_key) {
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
/* Report to callback */
|
||||
if (stun_sock->cb.on_data_sent) {
|
||||
pj_bool_t ret;
|
||||
|
||||
/* If app gives NULL send_key in sendto() function, then give
|
||||
* NULL in the callback too
|
||||
*/
|
||||
if (send_key == &stun_sock->send_key)
|
||||
send_key = NULL;
|
||||
|
||||
/* Call callback */
|
||||
ret = (*stun_sock->cb.on_data_sent)(stun_sock, send_key, sent);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
|
@ -31,16 +31,17 @@
|
|||
struct pj_stun_client_tsx
|
||||
{
|
||||
char obj_name[PJ_MAX_OBJ_NAME];
|
||||
pj_stun_config *cfg;
|
||||
pj_stun_tsx_cb cb;
|
||||
void *user_data;
|
||||
|
||||
pj_bool_t complete;
|
||||
|
||||
pj_bool_t require_retransmit;
|
||||
unsigned rto_msec;
|
||||
pj_timer_entry retransmit_timer;
|
||||
unsigned transmit_count;
|
||||
pj_time_val retransmit_time;
|
||||
pj_timer_heap_t *timer_heap;
|
||||
|
||||
pj_timer_entry destroy_timer;
|
||||
|
||||
|
@ -70,7 +71,8 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_create(pj_stun_config *cfg,
|
|||
PJ_ASSERT_RETURN(cb->on_send_msg, PJ_EINVAL);
|
||||
|
||||
tsx = PJ_POOL_ZALLOC_T(pool, pj_stun_client_tsx);
|
||||
tsx->cfg = cfg;
|
||||
tsx->rto_msec = cfg->rto_msec;
|
||||
tsx->timer_heap = cfg->timer_heap;
|
||||
pj_memcpy(&tsx->cb, cb, sizeof(*cb));
|
||||
|
||||
tsx->retransmit_timer.cb = &retransmit_timer_callback;
|
||||
|
@ -99,22 +101,23 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_schedule_destroy(
|
|||
|
||||
/* Cancel previously registered timer */
|
||||
if (tsx->destroy_timer.id != 0) {
|
||||
pj_timer_heap_cancel(tsx->cfg->timer_heap, &tsx->destroy_timer);
|
||||
pj_timer_heap_cancel(tsx->timer_heap, &tsx->destroy_timer);
|
||||
tsx->destroy_timer.id = 0;
|
||||
}
|
||||
|
||||
/* Stop retransmission, just in case */
|
||||
if (tsx->retransmit_timer.id != 0) {
|
||||
pj_timer_heap_cancel(tsx->cfg->timer_heap, &tsx->retransmit_timer);
|
||||
pj_timer_heap_cancel(tsx->timer_heap, &tsx->retransmit_timer);
|
||||
tsx->retransmit_timer.id = 0;
|
||||
}
|
||||
|
||||
status = pj_timer_heap_schedule(tsx->cfg->timer_heap,
|
||||
status = pj_timer_heap_schedule(tsx->timer_heap,
|
||||
&tsx->destroy_timer, delay);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
tsx->destroy_timer.id = TIMER_ACTIVE;
|
||||
tsx->cb.on_complete = NULL;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
@ -128,11 +131,11 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_destroy(pj_stun_client_tsx *tsx)
|
|||
PJ_ASSERT_RETURN(tsx, PJ_EINVAL);
|
||||
|
||||
if (tsx->retransmit_timer.id != 0) {
|
||||
pj_timer_heap_cancel(tsx->cfg->timer_heap, &tsx->retransmit_timer);
|
||||
pj_timer_heap_cancel(tsx->timer_heap, &tsx->retransmit_timer);
|
||||
tsx->retransmit_timer.id = 0;
|
||||
}
|
||||
if (tsx->destroy_timer.id != 0) {
|
||||
pj_timer_heap_cancel(tsx->cfg->timer_heap, &tsx->destroy_timer);
|
||||
pj_timer_heap_cancel(tsx->timer_heap, &tsx->destroy_timer);
|
||||
tsx->destroy_timer.id = 0;
|
||||
}
|
||||
|
||||
|
@ -186,7 +189,7 @@ static pj_status_t tsx_transmit_msg(pj_stun_client_tsx *tsx)
|
|||
/* Calculate retransmit/timeout delay */
|
||||
if (tsx->transmit_count == 0) {
|
||||
tsx->retransmit_time.sec = 0;
|
||||
tsx->retransmit_time.msec = tsx->cfg->rto_msec;
|
||||
tsx->retransmit_time.msec = tsx->rto_msec;
|
||||
|
||||
} else if (tsx->transmit_count < PJ_STUN_MAX_TRANSMIT_COUNT-1) {
|
||||
unsigned msec;
|
||||
|
@ -205,7 +208,7 @@ static pj_status_t tsx_transmit_msg(pj_stun_client_tsx *tsx)
|
|||
* cancel it (as opposed to when schedule_timer() failed we cannot
|
||||
* cancel transmission).
|
||||
*/;
|
||||
status = pj_timer_heap_schedule(tsx->cfg->timer_heap,
|
||||
status = pj_timer_heap_schedule(tsx->timer_heap,
|
||||
&tsx->retransmit_timer,
|
||||
&tsx->retransmit_time);
|
||||
if (status != PJ_SUCCESS) {
|
||||
|
@ -223,9 +226,12 @@ static pj_status_t tsx_transmit_msg(pj_stun_client_tsx *tsx)
|
|||
|
||||
/* Send message */
|
||||
status = tsx->cb.on_send_msg(tsx, tsx->last_pkt, tsx->last_pkt_size);
|
||||
if (status != PJ_SUCCESS) {
|
||||
|
||||
if (status == PJNATH_ESTUNDESTROYED) {
|
||||
/* We've been destroyed, don't access the object. */
|
||||
} else if (status != PJ_SUCCESS) {
|
||||
if (tsx->retransmit_timer.id != 0) {
|
||||
pj_timer_heap_cancel(tsx->cfg->timer_heap,
|
||||
pj_timer_heap_cancel(tsx->timer_heap,
|
||||
&tsx->retransmit_timer);
|
||||
tsx->retransmit_timer.id = 0;
|
||||
}
|
||||
|
@ -279,12 +285,15 @@ static void retransmit_timer_callback(pj_timer_heap_t *timer_heap,
|
|||
tsx->cb.on_complete(tsx, PJNATH_ESTUNTIMEDOUT, NULL, NULL, 0);
|
||||
}
|
||||
}
|
||||
/* We might have been destroyed, don't try to access the object */
|
||||
return;
|
||||
}
|
||||
|
||||
tsx->retransmit_timer.id = 0;
|
||||
status = tsx_transmit_msg(tsx);
|
||||
if (status != PJ_SUCCESS) {
|
||||
if (status == PJNATH_ESTUNDESTROYED) {
|
||||
/* We've been destroyed, don't try to access the object */
|
||||
} else if (status != PJ_SUCCESS) {
|
||||
tsx->retransmit_timer.id = 0;
|
||||
if (!tsx->complete) {
|
||||
tsx->complete = PJ_TRUE;
|
||||
|
@ -292,6 +301,7 @@ static void retransmit_timer_callback(pj_timer_heap_t *timer_heap,
|
|||
tsx->cb.on_complete(tsx, status, NULL, NULL, 0);
|
||||
}
|
||||
}
|
||||
/* We might have been destroyed, don't try to access the object */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,7 +315,7 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_retransmit(pj_stun_client_tsx *tsx)
|
|||
}
|
||||
|
||||
if (tsx->retransmit_timer.id != 0) {
|
||||
pj_timer_heap_cancel(tsx->cfg->timer_heap, &tsx->retransmit_timer);
|
||||
pj_timer_heap_cancel(tsx->timer_heap, &tsx->retransmit_timer);
|
||||
tsx->retransmit_timer.id = 0;
|
||||
}
|
||||
|
||||
|
@ -351,7 +361,7 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx,
|
|||
* We can cancel retransmit timer now.
|
||||
*/
|
||||
if (tsx->retransmit_timer.id) {
|
||||
pj_timer_heap_cancel(tsx->cfg->timer_heap, &tsx->retransmit_timer);
|
||||
pj_timer_heap_cancel(tsx->timer_heap, &tsx->retransmit_timer);
|
||||
tsx->retransmit_timer.id = 0;
|
||||
}
|
||||
|
||||
|
@ -384,6 +394,7 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx,
|
|||
if (tsx->cb.on_complete) {
|
||||
tsx->cb.on_complete(tsx, status, msg, src_addr, src_addr_len);
|
||||
}
|
||||
/* We might have been destroyed, don't try to access the object */
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
|
|
|
@ -29,8 +29,9 @@
|
|||
#include <pj/pool.h>
|
||||
#include <pj/sock.h>
|
||||
|
||||
#define MAX_SRV_CNT 4
|
||||
#define REFRESH_SEC_BEFORE 60
|
||||
#define PJ_TURN_CHANNEL_MIN 0x4000
|
||||
#define PJ_TURN_CHANNEL_MAX 0xFFFE /* inclusive */
|
||||
#define PJ_TURN_PEER_HTABLE_SIZE 8
|
||||
|
||||
static const char *state_names[] =
|
||||
{
|
||||
|
@ -66,11 +67,13 @@ struct pj_turn_session
|
|||
const char *obj_name;
|
||||
pj_turn_session_cb cb;
|
||||
void *user_data;
|
||||
pj_stun_config stun_cfg;
|
||||
|
||||
pj_lock_t *lock;
|
||||
int busy;
|
||||
|
||||
pj_turn_state_t state;
|
||||
pj_status_t last_status;
|
||||
pj_bool_t pending_destroy;
|
||||
pj_bool_t destroy_notified;
|
||||
|
||||
|
@ -87,7 +90,7 @@ struct pj_turn_session
|
|||
pj_uint16_t default_port;
|
||||
|
||||
pj_uint16_t af;
|
||||
pj_turn_tp_type tp_type;
|
||||
pj_turn_tp_type conn_type;
|
||||
pj_uint16_t srv_addr_cnt;
|
||||
pj_sockaddr *srv_addr_list;
|
||||
pj_sockaddr *srv_addr;
|
||||
|
@ -95,6 +98,7 @@ struct pj_turn_session
|
|||
pj_bool_t pending_alloc;
|
||||
pj_turn_alloc_param alloc_param;
|
||||
|
||||
pj_sockaddr mapped_addr;
|
||||
pj_sockaddr relay_addr;
|
||||
|
||||
pj_hash_table_t *peer_table;
|
||||
|
@ -176,13 +180,13 @@ PJ_DEF(const char*) pj_turn_state_name(pj_turn_state_t state)
|
|||
/*
|
||||
* Create TURN client session.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pj_turn_session_create( pj_stun_config *cfg,
|
||||
PJ_DEF(pj_status_t) pj_turn_session_create( const pj_stun_config *cfg,
|
||||
const char *name,
|
||||
int af,
|
||||
pj_turn_tp_type tp_type,
|
||||
pj_turn_tp_type conn_type,
|
||||
const pj_turn_session_cb *cb,
|
||||
void *user_data,
|
||||
unsigned options,
|
||||
void *user_data,
|
||||
pj_turn_session **p_sess)
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
|
@ -206,11 +210,14 @@ PJ_DEF(pj_status_t) pj_turn_session_create( pj_stun_config *cfg,
|
|||
sess->obj_name = pool->obj_name;
|
||||
sess->timer_heap = cfg->timer_heap;
|
||||
sess->af = (pj_uint16_t)af;
|
||||
sess->tp_type = tp_type;
|
||||
sess->conn_type = conn_type;
|
||||
sess->ka_interval = PJ_TURN_KEEP_ALIVE_SEC;
|
||||
sess->user_data = user_data;
|
||||
sess->next_ch = PJ_TURN_CHANNEL_MIN;
|
||||
|
||||
/* Copy STUN session */
|
||||
pj_memcpy(&sess->stun_cfg, cfg, sizeof(pj_stun_config));
|
||||
|
||||
/* Copy callback */
|
||||
pj_memcpy(&sess->cb, cb, sizeof(*cb));
|
||||
|
||||
|
@ -233,8 +240,8 @@ PJ_DEF(pj_status_t) pj_turn_session_create( pj_stun_config *cfg,
|
|||
stun_cb.on_send_msg = &stun_on_send_msg;
|
||||
stun_cb.on_request_complete = &stun_on_request_complete;
|
||||
stun_cb.on_rx_indication = &stun_on_rx_indication;
|
||||
status = pj_stun_session_create(cfg, sess->obj_name, &stun_cb, PJ_FALSE,
|
||||
&sess->stun);
|
||||
status = pj_stun_session_create(&sess->stun_cfg, sess->obj_name, &stun_cb,
|
||||
PJ_FALSE, &sess->stun);
|
||||
if (status != PJ_SUCCESS) {
|
||||
do_destroy(sess);
|
||||
return status;
|
||||
|
@ -333,9 +340,10 @@ static void sess_shutdown(pj_turn_session *sess,
|
|||
case PJ_TURN_STATE_NULL:
|
||||
break;
|
||||
case PJ_TURN_STATE_RESOLVING:
|
||||
pj_assert(sess->dns_async != NULL);
|
||||
pj_dns_resolver_cancel_query(sess->dns_async, PJ_FALSE);
|
||||
sess->dns_async = NULL;
|
||||
if (sess->dns_async != NULL) {
|
||||
pj_dns_resolver_cancel_query(sess->dns_async, PJ_FALSE);
|
||||
sess->dns_async = NULL;
|
||||
}
|
||||
break;
|
||||
case PJ_TURN_STATE_RESOLVED:
|
||||
break;
|
||||
|
@ -365,13 +373,13 @@ static void sess_shutdown(pj_turn_session *sess,
|
|||
/* Schedule destroy */
|
||||
pj_time_val delay = {0, 0};
|
||||
|
||||
set_state(sess, PJ_TURN_STATE_DESTROYING);
|
||||
|
||||
if (sess->timer.id != TIMER_NONE) {
|
||||
pj_timer_heap_cancel(sess->timer_heap, &sess->timer);
|
||||
sess->timer.id = TIMER_NONE;
|
||||
}
|
||||
|
||||
set_state(sess, PJ_TURN_STATE_DESTROYING);
|
||||
|
||||
sess->timer.id = TIMER_DESTROY;
|
||||
pj_timer_heap_schedule(sess->timer_heap, &sess->timer, &delay);
|
||||
}
|
||||
|
@ -400,6 +408,8 @@ PJ_DEF(pj_status_t) pj_turn_session_shutdown(pj_turn_session *sess)
|
|||
*/
|
||||
PJ_DEF(pj_status_t) pj_turn_session_destroy( pj_turn_session *sess)
|
||||
{
|
||||
PJ_ASSERT_RETURN(sess, PJ_EINVAL);
|
||||
|
||||
set_state(sess, PJ_TURN_STATE_DEALLOCATED);
|
||||
sess_shutdown(sess, PJ_SUCCESS);
|
||||
return PJ_SUCCESS;
|
||||
|
@ -419,15 +429,19 @@ PJ_DEF(pj_status_t) pj_turn_session_get_info( pj_turn_session *sess,
|
|||
pj_gettimeofday(&now);
|
||||
|
||||
info->state = sess->state;
|
||||
info->tp_type = sess->tp_type;
|
||||
info->conn_type = sess->conn_type;
|
||||
info->lifetime = sess->expiry.sec - now.sec;
|
||||
info->last_status = sess->last_status;
|
||||
|
||||
if (sess->srv_addr)
|
||||
pj_memcpy(&info->server, sess->srv_addr, sizeof(info->server));
|
||||
else
|
||||
pj_bzero(&info->server, sizeof(info->server));
|
||||
|
||||
pj_memcpy(&info->relay_addr, &sess->relay_addr, sizeof(sess->relay_addr));
|
||||
pj_memcpy(&info->mapped_addr, &sess->mapped_addr,
|
||||
sizeof(sess->mapped_addr));
|
||||
pj_memcpy(&info->relay_addr, &sess->relay_addr,
|
||||
sizeof(sess->relay_addr));
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
@ -453,6 +467,19 @@ PJ_DEF(void*) pj_turn_session_get_user_data(pj_turn_session *sess)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* Configure message logging. By default all flags are enabled.
|
||||
*
|
||||
* @param sess The TURN client session.
|
||||
* @param flags Bitmask combination of #pj_stun_sess_msg_log_flag
|
||||
*/
|
||||
PJ_DEF(void) pj_turn_session_set_log( pj_turn_session *sess,
|
||||
unsigned flags)
|
||||
{
|
||||
pj_stun_session_set_log(sess->stun, flags);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the server or domain name of the server.
|
||||
*/
|
||||
|
@ -461,6 +488,8 @@ PJ_DEF(pj_status_t) pj_turn_session_set_server( pj_turn_session *sess,
|
|||
int default_port,
|
||||
pj_dns_resolver *resolver)
|
||||
{
|
||||
pj_sockaddr tmp_addr;
|
||||
pj_bool_t is_ip_addr;
|
||||
pj_status_t status;
|
||||
|
||||
PJ_ASSERT_RETURN(sess && domain, PJ_EINVAL);
|
||||
|
@ -468,14 +497,20 @@ PJ_DEF(pj_status_t) pj_turn_session_set_server( pj_turn_session *sess,
|
|||
|
||||
pj_lock_acquire(sess->lock);
|
||||
|
||||
if (resolver) {
|
||||
/* See if "domain" contains just IP address */
|
||||
tmp_addr.addr.sa_family = sess->af;
|
||||
status = pj_inet_pton(sess->af, domain,
|
||||
pj_sockaddr_get_addr(&tmp_addr));
|
||||
is_ip_addr = (status == PJ_SUCCESS);
|
||||
|
||||
if (!is_ip_addr && resolver) {
|
||||
/* Resolve with DNS SRV resolution, and fallback to DNS A resolution
|
||||
* if default_port is specified.
|
||||
*/
|
||||
unsigned opt = 0;
|
||||
pj_str_t res_name;
|
||||
|
||||
switch (sess->tp_type) {
|
||||
switch (sess->conn_type) {
|
||||
case PJ_TURN_TP_UDP:
|
||||
res_name = pj_str("_turn._udp.");
|
||||
break;
|
||||
|
@ -501,6 +536,12 @@ PJ_DEF(pj_status_t) pj_turn_session_set_server( pj_turn_session *sess,
|
|||
(int)domain->slen, domain->ptr));
|
||||
set_state(sess, PJ_TURN_STATE_RESOLVING);
|
||||
|
||||
/* User may have destroyed us in the callback */
|
||||
if (sess->state != PJ_TURN_STATE_RESOLVING) {
|
||||
status = PJ_ECANCELLED;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
status = pj_dns_srv_resolve(domain, &res_name, default_port,
|
||||
sess->pool, resolver, opt, sess,
|
||||
&dns_srv_resolver_cb, &sess->dns_async);
|
||||
|
@ -520,12 +561,19 @@ PJ_DEF(pj_status_t) pj_turn_session_set_server( pj_turn_session *sess,
|
|||
PJ_ASSERT_RETURN(default_port>0 && default_port<65536, PJ_EINVAL);
|
||||
sess->default_port = (pj_uint16_t)default_port;
|
||||
|
||||
cnt = MAX_SRV_CNT;
|
||||
cnt = PJ_TURN_MAX_DNS_SRV_CNT;
|
||||
ai = (pj_addrinfo*)
|
||||
pj_pool_calloc(sess->pool, cnt, sizeof(pj_addrinfo));
|
||||
|
||||
PJ_LOG(5,(sess->obj_name, "Resolving %.*s with DNS A",
|
||||
(int)domain->slen, domain->ptr));
|
||||
set_state(sess, PJ_TURN_STATE_RESOLVING);
|
||||
|
||||
/* User may have destroyed us in the callback */
|
||||
if (sess->state != PJ_TURN_STATE_RESOLVING) {
|
||||
status = PJ_ECANCELLED;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
status = pj_getaddrinfo(sess->af, domain, &cnt, ai);
|
||||
if (status != PJ_SUCCESS)
|
||||
|
@ -636,7 +684,7 @@ PJ_DEF(pj_status_t) pj_turn_session_alloc(pj_turn_session *sess,
|
|||
|
||||
/* Send request */
|
||||
set_state(sess, PJ_TURN_STATE_ALLOCATING);
|
||||
retransmit = (sess->tp_type == PJ_TURN_TP_UDP);
|
||||
retransmit = (sess->conn_type == PJ_TURN_TP_UDP);
|
||||
status = pj_stun_session_send_msg(sess->stun, NULL, PJ_FALSE,
|
||||
retransmit, sess->srv_addr,
|
||||
pj_sockaddr_get_len(sess->srv_addr),
|
||||
|
@ -681,7 +729,7 @@ static void send_refresh(pj_turn_session *sess, int lifetime)
|
|||
}
|
||||
|
||||
status = pj_stun_session_send_msg(sess->stun, NULL, PJ_FALSE,
|
||||
(sess->tp_type==PJ_TURN_TP_UDP),
|
||||
(sess->conn_type==PJ_TURN_TP_UDP),
|
||||
sess->srv_addr,
|
||||
pj_sockaddr_get_len(sess->srv_addr),
|
||||
tdata);
|
||||
|
@ -833,7 +881,7 @@ PJ_DEF(pj_status_t) pj_turn_session_bind_channel(pj_turn_session *sess,
|
|||
* for future reference when we receive the ChannelBind response.
|
||||
*/
|
||||
status = pj_stun_session_send_msg(sess->stun, peer, PJ_FALSE,
|
||||
(sess->tp_type==PJ_TURN_TP_UDP),
|
||||
(sess->conn_type==PJ_TURN_TP_UDP),
|
||||
sess->srv_addr,
|
||||
pj_sockaddr_get_len(sess->srv_addr),
|
||||
tdata);
|
||||
|
@ -849,12 +897,12 @@ on_return:
|
|||
* The packet maybe a STUN packet or ChannelData packet.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess,
|
||||
const pj_uint8_t *pkt,
|
||||
unsigned pkt_len,
|
||||
pj_bool_t is_datagram)
|
||||
void *pkt,
|
||||
unsigned pkt_len)
|
||||
{
|
||||
pj_bool_t is_stun;
|
||||
pj_status_t status;
|
||||
pj_bool_t is_datagram;
|
||||
|
||||
/* Packet could be ChannelData or STUN message (response or
|
||||
* indication).
|
||||
|
@ -863,14 +911,16 @@ PJ_DEF(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess,
|
|||
/* Start locking the session */
|
||||
pj_lock_acquire(sess->lock);
|
||||
|
||||
is_datagram = (sess->conn_type==PJ_TURN_TP_UDP);
|
||||
|
||||
/* Quickly check if this is STUN message */
|
||||
is_stun = ((pkt[0] & 0xC0) == 0);
|
||||
is_stun = ((((pj_uint8_t*)pkt)[0] & 0xC0) == 0);
|
||||
|
||||
if (is_stun) {
|
||||
/* This looks like STUN, give it to the STUN session */
|
||||
unsigned options;
|
||||
|
||||
options = PJ_STUN_CHECK_PACKET;
|
||||
options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK;
|
||||
if (is_datagram)
|
||||
options |= PJ_STUN_IS_DATAGRAM;
|
||||
status=pj_stun_session_on_rx_pkt(sess->stun, pkt, pkt_len,
|
||||
|
@ -905,8 +955,8 @@ PJ_DEF(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess,
|
|||
}
|
||||
|
||||
/* Notify application */
|
||||
(*sess->cb.on_rx_data)(sess, pkt+sizeof(cd), cd.length,
|
||||
&peer->addr,
|
||||
(*sess->cb.on_rx_data)(sess, ((pj_uint8_t*)pkt)+sizeof(cd),
|
||||
cd.length, &peer->addr,
|
||||
pj_sockaddr_get_len(&peer->addr));
|
||||
|
||||
status = PJ_SUCCESS;
|
||||
|
@ -953,6 +1003,8 @@ static void on_session_fail( pj_turn_session *sess,
|
|||
pj_status_t status,
|
||||
const pj_str_t *reason)
|
||||
{
|
||||
sess->last_status = status;
|
||||
|
||||
do {
|
||||
pj_str_t reason1;
|
||||
char err_msg[PJ_ERR_MSG_SIZE];
|
||||
|
@ -1010,6 +1062,7 @@ static void on_allocate_success(pj_turn_session *sess,
|
|||
{
|
||||
const pj_stun_lifetime_attr *lf_attr;
|
||||
const pj_stun_relay_addr_attr *raddr_attr;
|
||||
const pj_stun_sockaddr_attr *mapped_attr;
|
||||
pj_str_t s;
|
||||
pj_time_val timeout;
|
||||
|
||||
|
@ -1071,6 +1124,12 @@ static void on_allocate_success(pj_turn_session *sess,
|
|||
"for now"));
|
||||
return;
|
||||
}
|
||||
if (raddr_attr && !pj_sockaddr_has_addr(&raddr_attr->sockaddr)) {
|
||||
on_session_fail(sess, method, PJNATH_EINSTUNMSG,
|
||||
pj_cstr(&s, "Error: Invalid IP address in "
|
||||
"RELAY-ADDRESS attribute"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Save relayed address */
|
||||
if (raddr_attr) {
|
||||
|
@ -1091,6 +1150,14 @@ static void on_allocate_success(pj_turn_session *sess,
|
|||
}
|
||||
}
|
||||
|
||||
/* Get mapped address */
|
||||
mapped_attr = (const pj_stun_sockaddr_attr*)
|
||||
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_MAPPED_ADDR, 0);
|
||||
if (mapped_attr) {
|
||||
pj_memcpy(&sess->mapped_addr, &mapped_attr->sockaddr,
|
||||
sizeof(mapped_attr->sockaddr));
|
||||
}
|
||||
|
||||
/* Success */
|
||||
|
||||
/* Cancel existing keep-alive timer, if any */
|
||||
|
@ -1132,6 +1199,17 @@ static void stun_on_request_complete(pj_stun_session *stun,
|
|||
sess = (pj_turn_session*)pj_stun_session_get_user_data(stun);
|
||||
|
||||
if (method == PJ_STUN_ALLOCATE_METHOD) {
|
||||
|
||||
/* Destroy if we have pending destroy request */
|
||||
if (sess->pending_destroy) {
|
||||
if (status == PJ_SUCCESS)
|
||||
sess->state = PJ_TURN_STATE_READY;
|
||||
else
|
||||
sess->state = PJ_TURN_STATE_DEALLOCATED;
|
||||
sess_shutdown(sess, PJ_SUCCESS);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handle ALLOCATE response */
|
||||
if (status==PJ_SUCCESS &&
|
||||
PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type))
|
||||
|
@ -1298,7 +1376,7 @@ static void dns_srv_resolver_cb(void *user_data,
|
|||
const pj_dns_srv_record *rec)
|
||||
{
|
||||
pj_turn_session *sess = (pj_turn_session*) user_data;
|
||||
unsigned i, cnt;
|
||||
unsigned i, cnt, tot_cnt;
|
||||
|
||||
/* Clear async resolver */
|
||||
sess->dns_async = NULL;
|
||||
|
@ -1309,11 +1387,27 @@ static void dns_srv_resolver_cb(void *user_data,
|
|||
return;
|
||||
}
|
||||
|
||||
/* Calculate total number of server entries in the response */
|
||||
tot_cnt = 0;
|
||||
for (i=0; i<rec->count; ++i) {
|
||||
tot_cnt += rec->entry[i].server.addr_count;
|
||||
}
|
||||
|
||||
if (tot_cnt > PJ_TURN_MAX_DNS_SRV_CNT)
|
||||
tot_cnt = PJ_TURN_MAX_DNS_SRV_CNT;
|
||||
|
||||
/* Allocate server entries */
|
||||
sess->srv_addr_list = (pj_sockaddr*)
|
||||
pj_pool_calloc(sess->pool, tot_cnt,
|
||||
sizeof(pj_sockaddr));
|
||||
|
||||
/* Copy results to server entries */
|
||||
for (i=0, cnt=0; i<rec->count && cnt<MAX_SRV_CNT; ++i) {
|
||||
for (i=0, cnt=0; i<rec->count && cnt<PJ_TURN_MAX_DNS_SRV_CNT; ++i) {
|
||||
unsigned j;
|
||||
|
||||
for (j=0; j<rec->entry[i].server.addr_count && cnt<MAX_SRV_CNT; ++j) {
|
||||
for (j=0; j<rec->entry[i].server.addr_count &&
|
||||
cnt<PJ_TURN_MAX_DNS_SRV_CNT; ++j)
|
||||
{
|
||||
pj_sockaddr_in *addr = &sess->srv_addr_list[cnt].ipv4;
|
||||
|
||||
addr->sin_family = sess->af;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <pjnath/turn_sock.h>
|
||||
#include <pj/activesock.h>
|
||||
#include <pj/assert.h>
|
||||
#include <pj/errno.h>
|
||||
#include <pj/lock.h>
|
||||
|
@ -50,11 +51,8 @@ struct pj_turn_sock
|
|||
|
||||
int af;
|
||||
pj_turn_tp_type conn_type;
|
||||
pj_sock_t sock;
|
||||
pj_ioqueue_key_t *key;
|
||||
pj_ioqueue_op_key_t read_key;
|
||||
pj_activesock_t *active_sock;
|
||||
pj_ioqueue_op_key_t send_key;
|
||||
pj_uint8_t pkt[PJ_TURN_MAX_PKT_LEN];
|
||||
};
|
||||
|
||||
|
||||
|
@ -71,18 +69,22 @@ static void turn_on_channel_bound(pj_turn_session *sess,
|
|||
unsigned addr_len,
|
||||
unsigned ch_num);
|
||||
static void turn_on_rx_data(pj_turn_session *sess,
|
||||
const pj_uint8_t *pkt,
|
||||
void *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *peer_addr,
|
||||
unsigned addr_len);
|
||||
static void turn_on_state(pj_turn_session *sess,
|
||||
pj_turn_state_t old_state,
|
||||
pj_turn_state_t new_state);
|
||||
static void on_read_complete(pj_ioqueue_key_t *key,
|
||||
pj_ioqueue_op_key_t *op_key,
|
||||
pj_ssize_t bytes_read);
|
||||
static void on_connect_complete(pj_ioqueue_key_t *key,
|
||||
pj_status_t status);
|
||||
|
||||
static pj_bool_t on_data_read(pj_activesock_t *asock,
|
||||
void *data,
|
||||
pj_size_t size,
|
||||
pj_status_t status,
|
||||
pj_size_t *remainder);
|
||||
static pj_bool_t on_connect_complete(pj_activesock_t *asock,
|
||||
pj_status_t status);
|
||||
|
||||
|
||||
|
||||
static void destroy(pj_turn_sock *turn_sock);
|
||||
|
@ -158,7 +160,7 @@ PJ_DEF(pj_status_t) pj_turn_sock_create(pj_stun_config *cfg,
|
|||
sess_cb.on_rx_data = &turn_on_rx_data;
|
||||
sess_cb.on_state = &turn_on_state;
|
||||
status = pj_turn_session_create(cfg, pool->obj_name, af, conn_type,
|
||||
&sess_cb, turn_sock, 0, &turn_sock->sess);
|
||||
&sess_cb, 0, turn_sock, &turn_sock->sess);
|
||||
if (status != PJ_SUCCESS) {
|
||||
destroy(turn_sock);
|
||||
return status;
|
||||
|
@ -187,13 +189,9 @@ static void destroy(pj_turn_sock *turn_sock)
|
|||
turn_sock->sess = NULL;
|
||||
}
|
||||
|
||||
if (turn_sock->key) {
|
||||
pj_ioqueue_unregister(turn_sock->key);
|
||||
turn_sock->key = NULL;
|
||||
turn_sock->sock = 0;
|
||||
} else if (turn_sock->sock) {
|
||||
pj_sock_close(turn_sock->sock);
|
||||
turn_sock->sock = 0;
|
||||
if (turn_sock->active_sock) {
|
||||
pj_activesock_close(turn_sock->active_sock);
|
||||
turn_sock->active_sock = NULL;
|
||||
}
|
||||
|
||||
if (turn_sock->lock) {
|
||||
|
@ -271,7 +269,8 @@ static void sess_fail(pj_turn_sock *turn_sock, const char *title,
|
|||
pj_status_t status)
|
||||
{
|
||||
show_err(turn_sock, title, status);
|
||||
pj_turn_session_destroy(turn_sock->sess);
|
||||
if (turn_sock->sess)
|
||||
pj_turn_session_destroy(turn_sock->sess);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -280,6 +279,7 @@ static void sess_fail(pj_turn_sock *turn_sock, const char *title,
|
|||
PJ_DEF(pj_status_t) pj_turn_sock_set_user_data( pj_turn_sock *turn_sock,
|
||||
void *user_data)
|
||||
{
|
||||
PJ_ASSERT_RETURN(turn_sock, PJ_EINVAL);
|
||||
turn_sock->user_data = user_data;
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
@ -289,6 +289,7 @@ PJ_DEF(pj_status_t) pj_turn_sock_set_user_data( pj_turn_sock *turn_sock,
|
|||
*/
|
||||
PJ_DEF(void*) pj_turn_sock_get_user_data(pj_turn_sock *turn_sock)
|
||||
{
|
||||
PJ_ASSERT_RETURN(turn_sock, NULL);
|
||||
return turn_sock->user_data;
|
||||
}
|
||||
|
||||
|
@ -296,7 +297,7 @@ PJ_DEF(void*) pj_turn_sock_get_user_data(pj_turn_sock *turn_sock)
|
|||
* Get info.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pj_turn_sock_get_info(pj_turn_sock *turn_sock,
|
||||
pj_turn_session_info *info)
|
||||
pj_turn_session_info *info)
|
||||
{
|
||||
PJ_ASSERT_RETURN(turn_sock && info, PJ_EINVAL);
|
||||
|
||||
|
@ -309,15 +310,41 @@ PJ_DEF(pj_status_t) pj_turn_sock_get_info(pj_turn_sock *turn_sock,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock the TURN socket. Application may need to call this function to
|
||||
* synchronize access to other objects to avoid deadlock.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pj_turn_sock_lock(pj_turn_sock *turn_sock)
|
||||
{
|
||||
return pj_lock_acquire(turn_sock->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock the TURN socket.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pj_turn_sock_unlock(pj_turn_sock *turn_sock)
|
||||
{
|
||||
return pj_lock_release(turn_sock->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set STUN message logging for this TURN session.
|
||||
*/
|
||||
PJ_DEF(void) pj_turn_sock_set_log( pj_turn_sock *turn_sock,
|
||||
unsigned flags)
|
||||
{
|
||||
pj_turn_session_set_log(turn_sock->sess, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pj_turn_sock_init(pj_turn_sock *turn_sock,
|
||||
const pj_str_t *domain,
|
||||
int default_port,
|
||||
pj_dns_resolver *resolver,
|
||||
const pj_stun_auth_cred *cred,
|
||||
const pj_turn_alloc_param *param)
|
||||
PJ_DEF(pj_status_t) pj_turn_sock_alloc(pj_turn_sock *turn_sock,
|
||||
const pj_str_t *domain,
|
||||
int default_port,
|
||||
pj_dns_resolver *resolver,
|
||||
const pj_stun_auth_cred *cred,
|
||||
const pj_turn_alloc_param *param)
|
||||
{
|
||||
pj_status_t status;
|
||||
|
||||
|
@ -392,16 +419,16 @@ PJ_DEF(pj_status_t) pj_turn_sock_bind_channel( pj_turn_sock *turn_sock,
|
|||
/*
|
||||
* Notification when outgoing TCP socket has been connected.
|
||||
*/
|
||||
static void on_connect_complete(pj_ioqueue_key_t *key,
|
||||
pj_status_t status)
|
||||
static pj_bool_t on_connect_complete(pj_activesock_t *asock,
|
||||
pj_status_t status)
|
||||
{
|
||||
pj_turn_sock *turn_sock;
|
||||
|
||||
turn_sock = (pj_turn_sock*) pj_ioqueue_get_user_data(key);
|
||||
turn_sock = (pj_turn_sock*) pj_activesock_get_user_data(asock);
|
||||
|
||||
if (status != PJ_SUCCESS) {
|
||||
sess_fail(turn_sock, "TCP connect() error", status);
|
||||
return;
|
||||
return PJ_FALSE;
|
||||
}
|
||||
|
||||
if (turn_sock->conn_type != PJ_TURN_TP_UDP) {
|
||||
|
@ -409,8 +436,8 @@ static void on_connect_complete(pj_ioqueue_key_t *key,
|
|||
}
|
||||
|
||||
/* Kick start pending read operation */
|
||||
pj_ioqueue_op_key_init(&turn_sock->read_key, sizeof(turn_sock->read_key));
|
||||
on_read_complete(turn_sock->key, &turn_sock->read_key, INIT);
|
||||
status = pj_activesock_start_read(asock, turn_sock->pool,
|
||||
PJ_TURN_MAX_PKT_LEN, 0);
|
||||
|
||||
/* Init send_key */
|
||||
pj_ioqueue_op_key_init(&turn_sock->send_key, sizeof(turn_sock->send_key));
|
||||
|
@ -419,56 +446,43 @@ static void on_connect_complete(pj_ioqueue_key_t *key,
|
|||
status = pj_turn_session_alloc(turn_sock->sess, &turn_sock->alloc_param);
|
||||
if (status != PJ_SUCCESS) {
|
||||
sess_fail(turn_sock, "Error sending ALLOCATE", status);
|
||||
return;
|
||||
return PJ_FALSE;
|
||||
}
|
||||
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Notification from ioqueue when incoming UDP 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)
|
||||
static pj_bool_t on_data_read(pj_activesock_t *asock,
|
||||
void *data,
|
||||
pj_size_t size,
|
||||
pj_status_t status,
|
||||
pj_size_t *remainder)
|
||||
{
|
||||
enum { MAX_RETRY = 10 };
|
||||
pj_turn_sock *turn_sock;
|
||||
int retry = 0;
|
||||
pj_status_t status;
|
||||
pj_bool_t ret = PJ_TRUE;
|
||||
|
||||
turn_sock = (pj_turn_sock*) pj_ioqueue_get_user_data(key);
|
||||
turn_sock = (pj_turn_sock*) pj_activesock_get_user_data(asock);
|
||||
pj_lock_acquire(turn_sock->lock);
|
||||
|
||||
do {
|
||||
if (bytes_read == INIT) {
|
||||
/* Special instruction to initialize pending read() */
|
||||
} else if (bytes_read > 0 && turn_sock->sess) {
|
||||
/* Report incoming packet to TURN session */
|
||||
pj_turn_session_on_rx_pkt(turn_sock->sess, turn_sock->pkt,
|
||||
bytes_read,
|
||||
turn_sock->conn_type == PJ_TURN_TP_UDP);
|
||||
} else if (bytes_read <= 0 && turn_sock->conn_type != PJ_TURN_TP_UDP) {
|
||||
sess_fail(turn_sock, "TCP connection closed", -bytes_read);
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/* Read next packet */
|
||||
bytes_read = sizeof(turn_sock->pkt);
|
||||
status = pj_ioqueue_recv(turn_sock->key, op_key,
|
||||
turn_sock->pkt, &bytes_read, 0);
|
||||
|
||||
if (status != PJ_EPENDING && status != PJ_SUCCESS) {
|
||||
char errmsg[PJ_ERR_MSG_SIZE];
|
||||
|
||||
pj_strerror(status, errmsg, sizeof(errmsg));
|
||||
sess_fail(turn_sock, "Socket recv() error", status);
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
} while (status != PJ_EPENDING && status != PJ_ECANCELLED &&
|
||||
++retry < MAX_RETRY);
|
||||
if (status == PJ_SUCCESS && turn_sock->sess) {
|
||||
/* Report incoming packet to TURN session */
|
||||
PJ_TODO(REPORT_PARSED_LEN);
|
||||
pj_turn_session_on_rx_pkt(turn_sock->sess, data, size);
|
||||
} else if (status != PJ_SUCCESS &&
|
||||
turn_sock->conn_type != PJ_TURN_TP_UDP)
|
||||
{
|
||||
sess_fail(turn_sock, "TCP connection closed", status);
|
||||
ret = PJ_FALSE;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
on_return:
|
||||
pj_lock_release(turn_sock->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -482,7 +496,7 @@ static pj_status_t turn_on_send_pkt(pj_turn_session *sess,
|
|||
unsigned dst_addr_len)
|
||||
{
|
||||
pj_turn_sock *turn_sock = (pj_turn_sock*)
|
||||
pj_turn_session_get_user_data(sess);
|
||||
pj_turn_session_get_user_data(sess);
|
||||
pj_ssize_t len = pkt_len;
|
||||
pj_status_t status;
|
||||
|
||||
|
@ -495,8 +509,8 @@ static pj_status_t turn_on_send_pkt(pj_turn_session *sess,
|
|||
PJ_UNUSED_ARG(dst_addr);
|
||||
PJ_UNUSED_ARG(dst_addr_len);
|
||||
|
||||
status = pj_ioqueue_send(turn_sock->key, &turn_sock->send_key,
|
||||
pkt, &len, 0);
|
||||
status = pj_activesock_send(turn_sock->active_sock, &turn_sock->send_key,
|
||||
pkt, &len, 0);
|
||||
if (status != PJ_SUCCESS && status != PJ_EPENDING) {
|
||||
show_err(turn_sock, "socket send()", status);
|
||||
}
|
||||
|
@ -524,7 +538,7 @@ static void turn_on_channel_bound(pj_turn_session *sess,
|
|||
* Callback from TURN session upon incoming data.
|
||||
*/
|
||||
static void turn_on_rx_data(pj_turn_session *sess,
|
||||
const pj_uint8_t *pkt,
|
||||
void *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *peer_addr,
|
||||
unsigned addr_len)
|
||||
|
@ -559,7 +573,19 @@ static void turn_on_state(pj_turn_session *sess,
|
|||
return;
|
||||
}
|
||||
|
||||
if (new_state == PJ_TURN_STATE_RESOLVED) {
|
||||
/* Notify app first */
|
||||
if (turn_sock->cb.on_state) {
|
||||
(*turn_sock->cb.on_state)(turn_sock, old_state, new_state);
|
||||
}
|
||||
|
||||
/* Make sure user hasn't destroyed us in the callback */
|
||||
if (turn_sock->sess && new_state == PJ_TURN_STATE_RESOLVED) {
|
||||
pj_turn_session_info info;
|
||||
pj_turn_session_get_info(turn_sock->sess, &info);
|
||||
new_state = info.state;
|
||||
}
|
||||
|
||||
if (turn_sock->sess && new_state == PJ_TURN_STATE_RESOLVED) {
|
||||
/*
|
||||
* Once server has been resolved, initiate outgoing TCP
|
||||
* connection to the server.
|
||||
|
@ -567,19 +593,16 @@ static void turn_on_state(pj_turn_session *sess,
|
|||
pj_turn_session_info info;
|
||||
char addrtxt[PJ_INET6_ADDRSTRLEN+8];
|
||||
int sock_type;
|
||||
pj_ioqueue_callback ioq_cb;
|
||||
pj_sock_t sock;
|
||||
pj_activesock_cb asock_cb;
|
||||
|
||||
/* Close existing connection, if any. This happens when
|
||||
* we're switching to alternate TURN server when either TCP
|
||||
* connection or ALLOCATE request failed.
|
||||
*/
|
||||
if (turn_sock->key) {
|
||||
pj_ioqueue_unregister(turn_sock->key);
|
||||
turn_sock->key = NULL;
|
||||
turn_sock->sock = 0;
|
||||
} else if (turn_sock->sock) {
|
||||
pj_sock_close(turn_sock->sock);
|
||||
turn_sock->sock = 0;
|
||||
if (turn_sock->active_sock) {
|
||||
pj_activesock_close(turn_sock->active_sock);
|
||||
turn_sock->active_sock = NULL;
|
||||
}
|
||||
|
||||
/* Get server address from session info */
|
||||
|
@ -591,20 +614,21 @@ static void turn_on_state(pj_turn_session *sess,
|
|||
sock_type = pj_SOCK_STREAM();
|
||||
|
||||
/* Init socket */
|
||||
status = pj_sock_socket(turn_sock->af, sock_type, 0,
|
||||
&turn_sock->sock);
|
||||
status = pj_sock_socket(turn_sock->af, sock_type, 0, &sock);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_turn_sock_destroy(turn_sock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Register to ioqeuue */
|
||||
pj_bzero(&ioq_cb, sizeof(ioq_cb));
|
||||
ioq_cb.on_read_complete = &on_read_complete;
|
||||
ioq_cb.on_connect_complete = &on_connect_complete;
|
||||
status = pj_ioqueue_register_sock(turn_sock->pool, turn_sock->cfg.ioqueue,
|
||||
turn_sock->sock, turn_sock,
|
||||
&ioq_cb, &turn_sock->key);
|
||||
/* Create active socket */
|
||||
pj_bzero(&asock_cb, sizeof(asock_cb));
|
||||
asock_cb.on_data_read = &on_data_read;
|
||||
asock_cb.on_connect_complete = &on_connect_complete;
|
||||
status = pj_activesock_create(turn_sock->pool, sock,
|
||||
sock_type, NULL,
|
||||
turn_sock->cfg.ioqueue, &asock_cb,
|
||||
turn_sock,
|
||||
&turn_sock->active_sock);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_turn_sock_destroy(turn_sock);
|
||||
return;
|
||||
|
@ -616,10 +640,12 @@ static void turn_on_state(pj_turn_session *sess,
|
|||
sizeof(addrtxt), 3)));
|
||||
|
||||
/* Initiate non-blocking connect */
|
||||
status = pj_ioqueue_connect(turn_sock->key, &info.server,
|
||||
pj_sockaddr_get_len(&info.server));
|
||||
status=pj_activesock_start_connect(turn_sock->active_sock,
|
||||
turn_sock->pool,
|
||||
&info.server,
|
||||
pj_sockaddr_get_len(&info.server));
|
||||
if (status == PJ_SUCCESS) {
|
||||
on_connect_complete(turn_sock->key, PJ_SUCCESS);
|
||||
on_connect_complete(turn_sock->active_sock, PJ_SUCCESS);
|
||||
} else if (status != PJ_EPENDING) {
|
||||
pj_turn_sock_destroy(turn_sock);
|
||||
return;
|
||||
|
@ -630,10 +656,6 @@ static void turn_on_state(pj_turn_session *sess,
|
|||
*/
|
||||
}
|
||||
|
||||
if (turn_sock->cb.on_state) {
|
||||
(*turn_sock->cb.on_state)(turn_sock, old_state, new_state);
|
||||
}
|
||||
|
||||
if (new_state >= PJ_TURN_STATE_DESTROYING && turn_sock->sess) {
|
||||
pj_time_val delay = {0, 0};
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ static struct options
|
|||
|
||||
static int worker_thread(void *unused);
|
||||
static void turn_on_rx_data(pj_turn_sock *relay,
|
||||
const pj_uint8_t *pkt,
|
||||
void *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *peer_addr,
|
||||
unsigned addr_len);
|
||||
|
@ -274,7 +274,7 @@ static pj_status_t create_relay(void)
|
|||
}
|
||||
|
||||
srv = pj_str(o.srv_addr);
|
||||
CHECK( pj_turn_sock_init(g.relay, /* the relay */
|
||||
CHECK(pj_turn_sock_alloc(g.relay, /* the relay */
|
||||
&srv, /* srv addr */
|
||||
(o.srv_port?atoi(o.srv_port):PJ_STUN_PORT),/* def port */
|
||||
NULL, /* resolver */
|
||||
|
@ -294,7 +294,7 @@ static void destroy_relay(void)
|
|||
|
||||
|
||||
static void turn_on_rx_data(pj_turn_sock *relay,
|
||||
const pj_uint8_t *pkt,
|
||||
void *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *peer_addr,
|
||||
unsigned addr_len)
|
||||
|
|
|
@ -35,8 +35,7 @@ static struct cred_t
|
|||
{
|
||||
{ "100", "100" },
|
||||
{ "700", "700" },
|
||||
{ "701", "701" },
|
||||
{ "702", "702" }
|
||||
{ "701", "701" }
|
||||
};
|
||||
|
||||
#define THE_NONCE "pjnath"
|
||||
|
|
Loading…
Reference in New Issue