summaryrefslogtreecommitdiff
path: root/pjnath
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-03-21 22:05:58 +0000
committerBenny Prijono <bennylp@teluu.com>2007-03-21 22:05:58 +0000
commit8befa349c02d1150d1140aefee97ebb47527da20 (patch)
tree720b371c8d7512311472e606d58a7017b3b85ff0 /pjnath
parent33fe5e64b9b0482a127d8137aae43e5e29e1adc8 (diff)
Added pjnath-test
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1093 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjnath')
-rw-r--r--pjnath/build/pjnath.dsp8
-rw-r--r--pjnath/build/pjnath.dsw21
-rw-r--r--pjnath/build/pjnath_test.dsp118
-rw-r--r--pjnath/include/pjnath.h2
-rw-r--r--pjnath/include/pjnath/ice.h27
-rw-r--r--pjnath/include/pjnath/ice_mt.h114
-rw-r--r--pjnath/src/pjnath-test/ice.c233
-rw-r--r--pjnath/src/pjnath-test/main.c53
-rw-r--r--pjnath/src/pjnath-test/stun.c118
-rw-r--r--pjnath/src/pjnath-test/test.c89
-rw-r--r--pjnath/src/pjnath-test/test.h30
-rw-r--r--pjnath/src/pjnath/ice.c20
-rw-r--r--pjnath/src/pjnath/ice_mt.c285
-rw-r--r--pjnath/src/pjnath/stun_msg.c2
14 files changed, 1094 insertions, 26 deletions
diff --git a/pjnath/build/pjnath.dsp b/pjnath/build/pjnath.dsp
index 999bf065..081f89ec 100644
--- a/pjnath/build/pjnath.dsp
+++ b/pjnath/build/pjnath.dsp
@@ -95,6 +95,10 @@ SOURCE=..\src\pjnath\ice.c
# End Source File
# Begin Source File
+SOURCE=..\src\pjnath\ice_mt.c
+# End Source File
+# Begin Source File
+
SOURCE=..\src\pjnath\stun_auth.c
# End Source File
# Begin Source File
@@ -131,6 +135,10 @@ SOURCE=..\include\pjnath\ice.h
# End Source File
# Begin Source File
+SOURCE=..\include\pjnath\ice_mt.h
+# End Source File
+# Begin Source File
+
SOURCE=..\include\pjnath.h
# End Source File
# Begin Source File
diff --git a/pjnath/build/pjnath.dsw b/pjnath/build/pjnath.dsw
index 03b80cd2..33252433 100644
--- a/pjnath/build/pjnath.dsw
+++ b/pjnath/build/pjnath.dsw
@@ -39,6 +39,27 @@ Package=<4>
###############################################################################
+Project: "pjnath_test"=.\pjnath_test.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name pjlib
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name pjlib_util
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name pjnath
+ End Project Dependency
+}}}
+
+###############################################################################
+
Project: "pjstun_client"=.\pjstun_client.dsp - Package Owner=<4>
Package=<5>
diff --git a/pjnath/build/pjnath_test.dsp b/pjnath/build/pjnath_test.dsp
new file mode 100644
index 00000000..4ce0e771
--- /dev/null
+++ b/pjnath/build/pjnath_test.dsp
@@ -0,0 +1,118 @@
+# Microsoft Developer Studio Project File - Name="pjnath_test" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=pjnath_test - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "pjnath_test.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "pjnath_test.mak" CFG="pjnath_test - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "pjnath_test - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "pjnath_test - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "pjnath_test - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "./output/pjnath-test-i386-win32-vc6-release"
+# PROP BASE Intermediate_Dir "./output/pjnath-test-i386-win32-vc6-release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "./output/pjnath-test-i386-win32-vc6-release"
+# PROP Intermediate_Dir "./output/pjnath-test-i386-win32-vc6-release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W4 /GX /O2 /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 netapi32.lib mswsock.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"../bin/pjnath-test-i386-win32-vc6-release.exe"
+
+!ELSEIF "$(CFG)" == "pjnath_test - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "./output/pjnath-test-i386-win32-vc6-debug"
+# PROP BASE Intermediate_Dir "./output/pjnath-test-i386-win32-vc6-debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "./output/pjnath-test-i386-win32-vc6-debug"
+# PROP Intermediate_Dir "./output/pjnath-test-i386-win32-vc6-debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 netapi32.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../bin/pjnath-test-i386-win32-vc6-debug.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "pjnath_test - Win32 Release"
+# Name "pjnath_test - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\src\pjnath-test\ice.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjnath-test\main.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjnath-test\stun.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjnath-test\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\test.h"
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/pjnath/include/pjnath.h b/pjnath/include/pjnath.h
index 750a613e..c3f85fc3 100644
--- a/pjnath/include/pjnath.h
+++ b/pjnath/include/pjnath.h
@@ -19,6 +19,8 @@
#include <pjnath/config.h>
#include <pjnath/errno.h>
+#include <pjnath/ice.h>
+#include <pjnath/ice_mt.h>
#include <pjnath/stun_auth.h>
#include <pjnath/stun_config.h>
#include <pjnath/stun_msg.h>
diff --git a/pjnath/include/pjnath/ice.h b/pjnath/include/pjnath/ice.h
index 568a2825..94cd7a22 100644
--- a/pjnath/include/pjnath/ice.h
+++ b/pjnath/include/pjnath/ice.h
@@ -20,23 +20,28 @@
#define __PJNATH_ICE_SOCK_H__
/**
- * @file ice_sock.h
- * @brief ICE socket.
+ * @file ice.h
+ * @brief ICE.
*/
#include <pjnath/types.h>
#include <pjnath/stun_session.h>
#include <pj/sock.h>
#include <pj/timer.h>
+/**
+ * @defgroup PJNATH_ICE Interactive Connectivity Establishment (ICE)
+ * @brief Interactive Connectivity Establishment (ICE)
+ * @ingroup PJNATH
+ */
+
PJ_BEGIN_DECL
-/* **************************************************************************/
/**
- * @defgroup PJNATH_ICE_SOCK ICE Socket
- * @brief High level ICE socket abstraction.
- * @ingroup PJNATH
+ * @defgroup PJNATH_ICE_STREAM Transport Independent ICE Media Stream
+ * @brief Transport Independent ICE Media Stream
+ * @ingroup PJNATH_ICE
* @{
*/
@@ -165,9 +170,8 @@ struct pj_ice
char obj_name[PJ_MAX_OBJ_NAME];
pj_pool_t *pool;
+ void *user_data;
pj_mutex_t *mutex;
- int af;
- int sock_type;
pj_ice_role role;
pj_bool_t is_complete;
pj_status_t ice_status;
@@ -176,8 +180,10 @@ struct pj_ice
pj_stun_config stun_cfg;
/* STUN credentials */
+ pj_str_t tx_ufrag;
pj_str_t tx_uname;
pj_str_t tx_pass;
+ pj_str_t rx_ufrag;
pj_str_t rx_uname;
pj_str_t rx_pass;
@@ -206,17 +212,12 @@ PJ_DECL(pj_status_t) pj_ice_create(pj_stun_config *stun_cfg,
const char *name,
pj_ice_role role,
const pj_ice_cb *cb,
- int af,
- int sock_type,
pj_ice **p_ice);
PJ_DECL(pj_status_t) pj_ice_destroy(pj_ice *ice);
PJ_DECL(pj_status_t) pj_ice_add_comp(pj_ice *ice,
unsigned comp_id,
const pj_sockaddr_t *local_addr,
unsigned addr_len);
-PJ_DECL(pj_status_t) pj_ice_add_sock_comp(pj_ice *ice,
- unsigned comp_id,
- pj_sock_t sock);
PJ_DECL(pj_status_t) pj_ice_set_credentials(pj_ice *ice,
const pj_str_t *local_ufrag,
const pj_str_t *local_pass,
diff --git a/pjnath/include/pjnath/ice_mt.h b/pjnath/include/pjnath/ice_mt.h
new file mode 100644
index 00000000..d96f39b6
--- /dev/null
+++ b/pjnath/include/pjnath/ice_mt.h
@@ -0,0 +1,114 @@
+/* $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_ICE_MT_H__
+#define __PJNATH_ICE_MT_H__
+
+
+/**
+ * @file ice_mt.h
+ * @brief ICE Media Transport.
+ */
+#include <pjnath/ice.h>
+#include <pj/ioqueue.h>
+
+
+PJ_BEGIN_DECL
+
+
+/**
+ * @defgroup PJNATH_ICE_MEDIA_TRANSPORT ICE Media Transport
+ * @brief ICE Media Transport
+ * @ingroup PJNATH_ICE
+ * @{
+ */
+
+typedef struct pj_icemt pj_icemt;
+
+typedef struct pj_icemt_cb
+{
+ void (*on_ice_complete)(pj_icemt *icemt,
+ pj_status_t status);
+ void (*on_rx_rtp)(pj_icemt *icemt,
+ void *pkt, pj_size_t size,
+ const pj_sockaddr_t *src_addr,
+ unsigned src_addr_len);
+ void (*on_rx_rtcp)(pj_icemt *icemt,
+ void *pkt, pj_size_t size,
+ const pj_sockaddr_t *src_addr,
+ unsigned src_addr_len);
+
+} pj_icemt_cb;
+
+
+typedef struct pj_icemt_sock
+{
+ pj_icemt *icemt;
+ unsigned comp_id;
+ pj_sock_t sock;
+ pj_sockaddr addr;
+ pj_sockaddr base_addr;
+ pj_ioqueue_key_t *key;
+ pj_uint8_t pkt[1500];
+ pj_ioqueue_op_key_t read_op;
+ pj_ioqueue_op_key_t write_op;
+ pj_sockaddr src_addr;
+ int src_addr_len;
+} pj_icemt_sock;
+
+
+struct pj_icemt
+{
+ pj_pool_t *pool;
+ pj_ice *ice;
+ void *user_data;
+
+ pj_icemt_cb cb;
+
+ pj_icemt_sock rtp;
+ pj_icemt_sock rtcp;
+
+ pj_bool_t has_turn;
+ pj_sockaddr stun_srv;
+};
+
+
+PJ_DECL(pj_status_t) pj_icemt_create(pj_stun_config *stun_cfg,
+ const char *name,
+ pj_ice_role role,
+ const pj_icemt_cb *cb,
+ unsigned rtp_port,
+ pj_bool_t has_rtcp,
+ pj_bool_t has_turn,
+ const pj_sockaddr *srv,
+ pj_icemt **p_icemt);
+PJ_DECL(pj_status_t) pj_icemt_destroy(pj_icemt *icemt);
+
+
+
+/**
+ * @}
+ */
+
+
+PJ_END_DECL
+
+
+
+#endif /* __PJNATH_ICE_MT_H__ */
+
diff --git a/pjnath/src/pjnath-test/ice.c b/pjnath/src/pjnath-test/ice.c
new file mode 100644
index 00000000..a6c19414
--- /dev/null
+++ b/pjnath/src/pjnath-test/ice.c
@@ -0,0 +1,233 @@
+/* $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 "ice.c"
+
+
+struct ice_data
+{
+ pj_bool_t complete;
+ pj_status_t err_code;
+ unsigned rx_rtp_cnt;
+ unsigned rx_rtcp_cnt;
+};
+
+static pj_stun_config stun_cfg;
+
+static void on_ice_complete(pj_icemt *icemt,
+ pj_status_t status)
+{
+ struct ice_data *id = (struct ice_data*) icemt->user_data;
+ id->complete = PJ_TRUE;
+ id->err_code = status;
+}
+
+
+static void on_rx_rtp(pj_icemt *icemt,
+ void *pkt, pj_size_t size,
+ const pj_sockaddr_t *src_addr,
+ unsigned src_addr_len)
+{
+ struct ice_data *id = (struct ice_data*) icemt->user_data;
+ id->rx_rtp_cnt++;
+}
+
+
+static void on_rx_rtcp(pj_icemt *icemt,
+ void *pkt, pj_size_t size,
+ const pj_sockaddr_t *src_addr,
+ unsigned src_addr_len)
+{
+ struct ice_data *id = (struct ice_data*) icemt->user_data;
+ id->rx_rtcp_cnt++;
+}
+
+
+static void handle_events(unsigned msec_timeout)
+{
+ pj_time_val delay;
+
+ pj_timer_heap_poll(stun_cfg.timer_heap, NULL);
+
+ delay.sec = 0;
+ delay.msec = msec_timeout;
+ pj_time_val_normalize(&delay);
+
+ pj_ioqueue_poll(stun_cfg.ioqueue, &delay);
+}
+
+
+/* Basic create and destroy test */
+static int ice_basic_create_destroy_test()
+{
+ pj_icemt *im;
+ pj_ice *ice;
+ pj_icemt_cb icemt_cb;
+ pj_status_t status;
+
+ PJ_LOG(3,(THIS_FILE, "...basic create/destroy"));
+
+ pj_bzero(&icemt_cb, sizeof(icemt_cb));
+ icemt_cb.on_ice_complete = &on_ice_complete;
+ icemt_cb.on_rx_rtcp = &on_rx_rtp;
+ icemt_cb.on_rx_rtcp = &on_rx_rtcp;
+
+ status = pj_icemt_create(&stun_cfg, NULL, PJ_ICE_ROLE_CONTROLLING,
+ &icemt_cb, 0, PJ_FALSE, PJ_FALSE, NULL, &im);
+ if (status != PJ_SUCCESS)
+ return -10;
+
+ ice = im->ice;
+
+ pj_icemt_destroy(im);
+
+ return 0;
+}
+
+
+static pj_status_t set_remote_list(pj_icemt *src, pj_icemt *dst)
+{
+ unsigned i, count;
+ unsigned cand_id[PJ_ICE_MAX_CAND];
+ pj_ice_cand cand[PJ_ICE_MAX_CAND];
+ pj_status_t status;
+
+ count = PJ_ARRAY_SIZE(cand_id);
+ status = pj_ice_enum_cands(src->ice, &count, cand_id);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ for (i=0; i<count; ++i) {
+ pj_ice_cand *p_cand;
+ status = pj_ice_get_cand(src->ice, cand_id[i], &p_cand);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ pj_memcpy(&cand[i], p_cand, sizeof(pj_ice_cand));
+ }
+
+ status = pj_ice_create_check_list(dst->ice, count, cand);
+ return status;
+}
+
+
+/* Direct agent to agent communication */
+static int ice_direct_test()
+{
+ pj_icemt *im1, *im2;
+ pj_icemt_cb icemt_cb;
+ struct ice_data *id1, *id2;
+ pj_status_t status;
+
+ PJ_LOG(3,(THIS_FILE, "...direct communication"));
+
+ pj_bzero(&icemt_cb, sizeof(icemt_cb));
+ icemt_cb.on_ice_complete = &on_ice_complete;
+ icemt_cb.on_rx_rtcp = &on_rx_rtp;
+ icemt_cb.on_rx_rtcp = &on_rx_rtcp;
+
+ /* Create first ICE */
+ status = pj_icemt_create(&stun_cfg, NULL, PJ_ICE_ROLE_CONTROLLING,
+ &icemt_cb, 0, PJ_FALSE, PJ_FALSE, NULL, &im1);
+ if (status != PJ_SUCCESS)
+ return -20;
+
+ id1 = PJ_POOL_ZALLOC_T(im1->pool, struct ice_data);
+ im1->user_data = id1;
+
+ /* Create second ICE */
+ status = pj_icemt_create(&stun_cfg, NULL, PJ_ICE_ROLE_CONTROLLED,
+ &icemt_cb, 0, PJ_FALSE, PJ_FALSE, NULL, &im2);
+ if (status != PJ_SUCCESS)
+ return -25;
+
+ id2 = PJ_POOL_ZALLOC_T(im2->pool, struct ice_data);
+ im2->user_data = id2;
+
+ {
+ pj_str_t u1 = pj_str("uname1");
+ pj_str_t p1 = pj_str("pass1");
+ pj_str_t u2 = pj_str("uname2");
+ pj_str_t p2 = pj_str("pass2");
+
+ pj_ice_set_credentials(im1->ice, &u1, &p1, &u2, &p2);
+ pj_ice_set_credentials(im2->ice, &u2, &p2, &u1, &p1);
+ }
+
+ /* Send offer to im2 */
+ status = set_remote_list(im1, im2);
+ if (status != PJ_SUCCESS)
+ return -30;
+
+ /* Send answer to im1 */
+ status = set_remote_list(im2, im1);
+ if (status != PJ_SUCCESS)
+ return -35;
+
+ /* Both can start now */
+ status = pj_ice_start_check(im1->ice);
+ if (status != PJ_SUCCESS)
+ return -40;
+
+#if 0
+ status = pj_ice_start_check(im2->ice);
+ if (status != PJ_SUCCESS)
+ return -40;
+#endif
+
+ /* Just wait until both completes, or timed out */
+ while (!id1->complete || !id2->complete)
+ handle_events(1);
+
+ return 0;
+
+}
+
+
+int ice_test(void)
+{
+ int rc = 0;
+ pj_pool_t *pool;
+ pj_ioqueue_t *ioqueue;
+ pj_timer_heap_t *timer_heap;
+
+ pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);
+ pj_ioqueue_create(pool, 12, &ioqueue);
+ pj_timer_heap_create(pool, 100, &timer_heap);
+
+ pj_stun_config_init(&stun_cfg, mem, 0, ioqueue, timer_heap);
+
+ pj_log_set_level(5);
+
+ rc = ice_basic_create_destroy_test();
+ if (rc != 0)
+ goto on_return;
+
+ rc = ice_direct_test();
+ if (rc != 0)
+ goto on_return;
+
+on_return:
+ pj_log_set_level(3);
+ pj_ioqueue_destroy(stun_cfg.ioqueue);
+ pj_pool_release(pool);
+ return rc;
+}
+
diff --git a/pjnath/src/pjnath-test/main.c b/pjnath/src/pjnath-test/main.c
new file mode 100644
index 00000000..33583e30
--- /dev/null
+++ b/pjnath/src/pjnath-test/main.c
@@ -0,0 +1,53 @@
+/* $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"
+
+#if defined(PJ_SUNOS) && PJ_SUNOS!=0
+#include <signal.h>
+static void init_signals()
+{
+ struct sigaction act;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = SIG_IGN;
+
+ sigaction(SIGALRM, &act, NULL);
+}
+
+#else
+#define init_signals()
+#endif
+
+#define boost()
+
+int main(int argc, char *argv[])
+{
+ int rc;
+
+ PJ_UNUSED_ARG(argc);
+ PJ_UNUSED_ARG(argv);
+
+ boost();
+ init_signals();
+
+ rc = test_main();
+
+ return rc;
+}
+
diff --git a/pjnath/src/pjnath-test/stun.c b/pjnath/src/pjnath-test/stun.c
new file mode 100644
index 00000000..230e51e7
--- /dev/null
+++ b/pjnath/src/pjnath-test/stun.c
@@ -0,0 +1,118 @@
+/* $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
+ */
+
+static int decode_test(void)
+{
+ /* Invalid message type */
+
+ /* Short message */
+
+ /* Long, random message */
+
+ /* Message length in header is shorter */
+
+ /* Message length in header is longer */
+
+ /* Invalid magic */
+
+ /* Attribute length is not valid */
+
+ /* Unknown mandatory attribute type should generate error */
+
+ /* Unknown but non-mandatory should be okay */
+
+ /* String/binary attribute length is larger than the message */
+
+ /* Valid message with MESSAGE-INTEGRITY */
+
+ /* Valid message with FINGERPRINT */
+
+ /* Valid message with MESSAGE-INTEGRITY and FINGERPRINT */
+
+ /* Another attribute not FINGERPRINT exists after MESSAGE-INTEGRITY */
+
+ /* Another attribute exists after FINGERPRINT */
+
+ return 0;
+}
+
+static int decode_verify(void)
+{
+ /* Decode all attribute types */
+ return 0;
+}
+
+static int auth_test(void)
+{
+ /* REALM and USERNAME is present, but MESSAGE-INTEGRITY is not present.
+ * For short term, must with reply 401 without REALM.
+ * For long term, must reply with 401 with REALM.
+ */
+
+ /* USERNAME is not present, server must respond with 432 (Missing
+ * Username).
+ */
+
+ /* If long term credential is wanted and REALM is not present, server
+ * must respond with 434 (Missing Realm)
+ */
+
+ /* If REALM doesn't match, server must respond with 434 (Missing Realm)
+ * too, containing REALM and NONCE attribute.
+ */
+
+ /* When long term authentication is wanted and NONCE is NOT present,
+ * server must respond with 435 (Missing Nonce), containing REALM and
+ * NONCE attribute.
+ */
+
+ /* Simulate 438 (Stale Nonce) */
+
+ /* Simulate 436 (Unknown Username) */
+
+ /* When server wants to use short term credential, but request has
+ * REALM, reject with .... ???
+ */
+
+ /* Invalid HMAC */
+
+ /* Valid static short term, without NONCE */
+
+ /* Valid static short term, WITH NONCE */
+
+ /* Valid static long term (with NONCE */
+
+ /* Valid dynamic short term (without NONCE) */
+
+ /* Valid dynamic short term (with NONCE) */
+
+ /* Valid dynamic long term (with NONCE) */
+
+ return 0;
+}
+
+
+int stun_test(void)
+{
+ decode_verify();
+ decode_test();
+ auth_test();
+ return 0;
+}
+
diff --git a/pjnath/src/pjnath-test/test.c b/pjnath/src/pjnath-test/test.c
new file mode 100644
index 00000000..6cc829d5
--- /dev/null
+++ b/pjnath/src/pjnath-test/test.c
@@ -0,0 +1,89 @@
+/* $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 <pjlib.h>
+
+void app_perror(const char *msg, pj_status_t rc)
+{
+ char errbuf[256];
+
+ PJ_CHECK_STACK();
+
+ pj_strerror(rc, errbuf, sizeof(errbuf));
+ PJ_LOG(1,("test", "%s: [pj_status_t=%d] %s", msg, rc, errbuf));
+}
+
+#define DO_TEST(test) do { \
+ PJ_LOG(3, ("test", "Running %s...", #test)); \
+ rc = test; \
+ PJ_LOG(3, ("test", \
+ "%s(%d)", \
+ (char*)(rc ? "..ERROR" : "..success"), rc)); \
+ if (rc!=0) goto on_return; \
+ } while (0)
+
+
+pj_pool_factory *mem;
+
+
+static int test_inner(void)
+{
+ pj_caching_pool caching_pool;
+ int rc = 0;
+
+ mem = &caching_pool.factory;
+
+ pj_log_set_level(3);
+ pj_log_set_decor(PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME |
+ PJ_LOG_HAS_MICRO_SEC);
+
+ rc = pj_init();
+ if (rc != 0) {
+ app_perror("pj_init() error!!", rc);
+ return rc;
+ }
+
+ pj_dump_config();
+ pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 );
+
+#if INCLUDE_ICE_TEST
+ DO_TEST(ice_test());
+#endif
+
+on_return:
+ return rc;
+}
+
+int test_main(void)
+{
+ PJ_USE_EXCEPTION;
+
+ PJ_TRY {
+ return test_inner();
+ }
+ PJ_CATCH_ANY {
+ int id = PJ_GET_EXCEPTION();
+ PJ_LOG(3,("test", "FATAL: unhandled exception id %d (%s)",
+ id, pj_exception_id_name(id)));
+ }
+ PJ_END;
+
+ return -1;
+}
+
diff --git a/pjnath/src/pjnath-test/test.h b/pjnath/src/pjnath-test/test.h
new file mode 100644
index 00000000..5663a84e
--- /dev/null
+++ b/pjnath/src/pjnath-test/test.h
@@ -0,0 +1,30 @@
+/* $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 <pjlib.h>
+#include <pjlib-util.h>
+#include <pjnath.h>
+
+#define INCLUDE_ICE_TEST 1
+
+extern int ice_test(void);
+extern int test_main(void);
+
+extern void app_perror(const char *title, pj_status_t rc);
+extern pj_pool_factory *mem;
+
diff --git a/pjnath/src/pjnath/ice.c b/pjnath/src/pjnath/ice.c
index e5d8fb6f..b0ba0f3d 100644
--- a/pjnath/src/pjnath/ice.c
+++ b/pjnath/src/pjnath/ice.c
@@ -136,8 +136,6 @@ PJ_DEF(pj_status_t) pj_ice_create(pj_stun_config *stun_cfg,
const char *name,
pj_ice_role role,
const pj_ice_cb *cb,
- int af,
- int sock_type,
pj_ice **p_ice)
{
pj_pool_t *pool;
@@ -146,8 +144,6 @@ PJ_DEF(pj_status_t) pj_ice_create(pj_stun_config *stun_cfg,
pj_status_t status;
PJ_ASSERT_RETURN(stun_cfg && cb && p_ice, PJ_EINVAL);
- PJ_ASSERT_RETURN(sock_type==PJ_SOCK_DGRAM || sock_type==PJ_SOCK_STREAM,
- PJ_EINVAL);
if (!name)
name = "ice%p";
@@ -155,8 +151,6 @@ PJ_DEF(pj_status_t) pj_ice_create(pj_stun_config *stun_cfg,
pool = pj_pool_create(stun_cfg->pf, name, 4000, 4000, NULL);
ice = PJ_POOL_ZALLOC_T(pool, pj_ice);
ice->pool = pool;
- ice->af = af;
- ice->sock_type = sock_type;
ice->role = role;
pj_ansi_snprintf(ice->obj_name, sizeof(ice->obj_name),
@@ -435,6 +429,7 @@ PJ_DEF(pj_status_t) pj_ice_set_credentials(pj_ice *ice,
pj_strcat(&username, local_ufrag);
pj_strdup(ice->pool, &ice->tx_uname, &username);
+ pj_strdup(ice->pool, &ice->tx_ufrag, remote_ufrag);
pj_strdup(ice->pool, &ice->tx_pass, remote_pass);
pj_strcpy(&username, local_ufrag);
@@ -442,6 +437,7 @@ PJ_DEF(pj_status_t) pj_ice_set_credentials(pj_ice *ice,
pj_strcat(&username, remote_ufrag);
pj_strdup(ice->pool, &ice->rx_uname, &username);
+ pj_strdup(ice->pool, &ice->rx_ufrag, local_ufrag);
pj_strdup(ice->pool, &ice->rx_pass, local_pass);
return PJ_SUCCESS;
@@ -481,7 +477,7 @@ PJ_DEF(pj_status_t) pj_ice_add_cand(pj_ice *ice,
pj_status_t status = PJ_SUCCESS;
char tmp[128];
- PJ_ASSERT_RETURN(ice && comp_id && type && local_pref &&
+ PJ_ASSERT_RETURN(ice && comp_id && local_pref &&
foundation && addr && base_addr && addr_len,
PJ_EINVAL);
@@ -703,7 +699,7 @@ static void dump_checklist(const char *title, const pj_ice *ice,
LOG((ice->obj_name, "%s", title));
for (i=0; i<clist->count; ++i) {
const pj_ice_check *c = &clist->checks[i];
- LOG((ice->obj_name, " %d: %s (prio=%u, state=%s)",
+ LOG((ice->obj_name, " %d: %s (prio=0x%"PJ_INT64_FMT"x, state=%s)",
i, dump_check(buffer, sizeof(buffer), c),
c->prio, check_state_name[c->state]));
}
@@ -1101,7 +1097,7 @@ static pj_status_t perform_check(pj_ice *ice, pj_ice_checklist *clist,
check = &clist->checks[check_id];
lcand = check->lcand;
rcand = check->rcand;
- comp = &ice->comp[lcand->comp_id];
+ comp = find_comp(ice, lcand->comp_id);
LOG((ice->obj_name,
"Sending connectivity check for check %d: %s",
@@ -1733,7 +1729,7 @@ PJ_DEF(pj_status_t) pj_ice_on_rx_pkt( pj_ice *ice,
{
pj_status_t status = PJ_SUCCESS;
pj_ice_comp *comp;
- pj_bool_t is_stun;
+ pj_status_t stun_status;
PJ_ASSERT_RETURN(ice, PJ_EINVAL);
@@ -1745,8 +1741,8 @@ PJ_DEF(pj_status_t) pj_ice_on_rx_pkt( pj_ice *ice,
goto on_return;
}
- is_stun = pj_stun_msg_check(pkt, pkt_size, PJ_STUN_IS_DATAGRAM);
- if (is_stun) {
+ stun_status = pj_stun_msg_check(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, src_addr, src_addr_len);
diff --git a/pjnath/src/pjnath/ice_mt.c b/pjnath/src/pjnath/ice_mt.c
new file mode 100644
index 00000000..000873be
--- /dev/null
+++ b/pjnath/src/pjnath/ice_mt.c
@@ -0,0 +1,285 @@
+/* $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/ice_mt.h>
+#include <pjnath/errno.h>
+#include <pj/addr_resolv.h>
+#include <pj/assert.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+
+
+#define RTP_COMP_ID 1
+#define RTCP_COMP_ID 2
+
+
+
+/* ICE callbacks */
+static void on_ice_complete(pj_ice *ice, pj_status_t status);
+static pj_status_t on_tx_pkt(pj_ice *ice, unsigned comp_id,
+ const void *pkt, pj_size_t size,
+ const pj_sockaddr_t *dst_addr,
+ unsigned dst_addr_len);
+static pj_status_t on_rx_data(pj_ice *ice, unsigned comp_id,
+ void *pkt, pj_size_t size,
+ const pj_sockaddr_t *src_addr,
+ unsigned src_addr_len);
+
+/* Ioqueue callback */
+static void on_read_complete(pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_ssize_t bytes_read);
+
+static void destroy_ice_sock(pj_icemt_sock *is);
+
+static pj_status_t create_ice_sock(pj_icemt *icemt,
+ pj_ioqueue_t *ioqueue,
+ unsigned comp_id,
+ unsigned port,
+ pj_icemt_sock *is)
+{
+ pj_ioqueue_callback ioqueue_cb;
+ const pj_str_t H1 = { "H1", 2 };
+ int addr_len;
+ pj_status_t status;
+
+ pj_bzero(is, sizeof(*is));
+ is->sock = PJ_INVALID_SOCKET;
+ is->comp_id = comp_id;
+ is->icemt = icemt;
+
+ status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &is->sock);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Bind and get the local IP address */
+ pj_sockaddr_in_init(&is->base_addr.ipv4, NULL, (pj_uint16_t)port);
+ status = pj_sock_bind(is->sock, &is->base_addr, sizeof(pj_sockaddr_in));
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ addr_len = sizeof(is->base_addr);
+ status = pj_sock_getsockname(is->sock, &is->base_addr, &addr_len);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ if (is->base_addr.ipv4.sin_addr.s_addr == 0) {
+ status = pj_gethostip(&is->base_addr.ipv4.sin_addr);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+ }
+
+ /* Register to ioqueue */
+ pj_bzero(&ioqueue_cb, sizeof(ioqueue_cb));
+ ioqueue_cb.on_read_complete = &on_read_complete;
+ status = pj_ioqueue_register_sock(icemt->pool, ioqueue, is->sock, is,
+ &ioqueue_cb, &is->key);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ pj_ioqueue_op_key_init(&is->read_op, sizeof(is->read_op));
+ pj_ioqueue_op_key_init(&is->write_op, sizeof(is->write_op));
+
+ on_read_complete(is->key, &is->read_op, 0);
+
+ /* Add new ICE component */
+ status = pj_ice_add_comp(icemt->ice, comp_id, &is->base_addr,
+ sizeof(pj_sockaddr_in));
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Add host candidate */
+ status = pj_ice_add_cand(icemt->ice, comp_id, PJ_ICE_CAND_TYPE_HOST,
+ 65535, &H1, &is->base_addr, &is->base_addr,
+ NULL, sizeof(pj_sockaddr_in), NULL);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ return PJ_SUCCESS;
+
+on_error:
+ destroy_ice_sock(is);
+ return status;
+}
+
+
+static void on_read_complete(pj_ioqueue_key_t *key,
+ pj_ioqueue_op_key_t *op_key,
+ pj_ssize_t bytes_read)
+{
+ pj_icemt_sock *is = (pj_icemt_sock*) pj_ioqueue_get_user_data(key);
+ pj_ssize_t pkt_size;
+ pj_status_t status;
+
+ if (bytes_read > 0) {
+ status = pj_ice_on_rx_pkt(is->icemt->ice, is->comp_id,
+ is->pkt, bytes_read,
+ &is->src_addr, is->src_addr_len);
+ }
+
+ pkt_size = sizeof(is->pkt);
+ is->src_addr_len = sizeof(is->src_addr);
+ status = pj_ioqueue_recvfrom(key, op_key, is->pkt, &pkt_size,
+ PJ_IOQUEUE_ALWAYS_ASYNC,
+ &is->src_addr, &is->src_addr_len);
+ pj_assert(status == PJ_SUCCESS || status == PJ_EPENDING);
+}
+
+
+static void destroy_ice_sock(pj_icemt_sock *is)
+{
+ if (is->key) {
+ pj_ioqueue_unregister(is->key);
+ is->key = NULL;
+ is->sock = PJ_INVALID_SOCKET;
+ } else if (is->sock != PJ_INVALID_SOCKET && is->sock != 0) {
+ pj_sock_close(is->sock);
+ is->sock = PJ_INVALID_SOCKET;
+ }
+}
+
+
+PJ_DEF(pj_status_t) pj_icemt_create( pj_stun_config *stun_cfg,
+ const char *name,
+ pj_ice_role role,
+ const pj_icemt_cb *cb,
+ unsigned rtp_port,
+ pj_bool_t has_rtcp,
+ pj_bool_t has_turn,
+ const pj_sockaddr *srv,
+ pj_icemt **p_icemt)
+{
+ pj_pool_t *pool;
+ pj_icemt *icemt;
+ pj_ice_cb ice_cb;
+ pj_status_t status;
+
+ pool = pj_pool_create(stun_cfg->pf, name, 512, 512, NULL);
+ icemt = PJ_POOL_ZALLOC_T(pool, struct pj_icemt);
+ icemt->pool = pool;
+
+
+ pj_bzero(&ice_cb, sizeof(ice_cb));
+ ice_cb.on_ice_complete = &on_ice_complete;
+ ice_cb.on_tx_pkt = &on_tx_pkt;
+ ice_cb.on_rx_data = &on_rx_data;
+
+ pj_memcpy(&icemt->cb, cb, sizeof(*cb));
+
+ status = pj_ice_create(stun_cfg, name, role, &ice_cb, &icemt->ice);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ icemt->ice->user_data = (void*)icemt;
+
+ icemt->has_turn = has_turn;
+ if (srv)
+ pj_memcpy(&icemt->stun_srv, srv, sizeof(pj_sockaddr));
+
+ status = create_ice_sock(icemt, stun_cfg->ioqueue, RTP_COMP_ID,
+ rtp_port, &icemt->rtp);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ if (has_rtcp) {
+ if (rtp_port) ++rtp_port;
+
+ status = create_ice_sock(icemt, stun_cfg->ioqueue, RTCP_COMP_ID,
+ rtp_port, &icemt->rtcp);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+ }
+
+ *p_icemt = icemt;
+ return PJ_SUCCESS;
+
+on_error:
+ if (icemt->ice)
+ pj_ice_destroy(icemt->ice);
+ pj_pool_release(pool);
+ return status;
+}
+
+
+PJ_DEF(pj_status_t) pj_icemt_destroy(pj_icemt *icemt)
+{
+ destroy_ice_sock(&icemt->rtp);
+ destroy_ice_sock(&icemt->rtcp);
+
+ pj_ice_destroy(icemt->ice);
+ pj_pool_release(icemt->pool);
+
+ return PJ_SUCCESS;
+}
+
+
+static void on_ice_complete(pj_ice *ice, pj_status_t status)
+{
+ pj_icemt *icemt = (pj_icemt*)ice->user_data;
+ (*icemt->cb.on_ice_complete)(icemt, status);
+}
+
+
+static pj_status_t on_tx_pkt(pj_ice *ice, unsigned comp_id,
+ const void *pkt, pj_size_t size,
+ const pj_sockaddr_t *dst_addr,
+ unsigned dst_addr_len)
+{
+ pj_icemt *icemt = (pj_icemt*)ice->user_data;
+ pj_icemt_sock *is;
+ pj_ssize_t pkt_size;
+ pj_status_t status;
+
+ if (comp_id == RTP_COMP_ID)
+ is = &icemt->rtp;
+ else if (comp_id == RTCP_COMP_ID)
+ is = &icemt->rtcp;
+ else {
+ pj_assert(!"Invalid comp_id");
+ return -1;
+ }
+
+ pkt_size = size;
+ status = pj_ioqueue_sendto(is->key, &is->write_op,
+ pkt, &pkt_size, 0,
+ dst_addr, dst_addr_len);
+
+ return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status;
+}
+
+
+static pj_status_t on_rx_data(pj_ice *ice, unsigned comp_id,
+ void *pkt, pj_size_t size,
+ const pj_sockaddr_t *src_addr,
+ unsigned src_addr_len)
+{
+ pj_icemt *icemt = (pj_icemt*)ice->user_data;
+
+ if (comp_id == RTP_COMP_ID) {
+ (*icemt->cb.on_rx_rtp)(icemt, pkt, size, src_addr, src_addr_len);
+ } else if (comp_id == RTCP_COMP_ID) {
+ (*icemt->cb.on_rx_rtcp)(icemt, pkt, size, src_addr, src_addr_len);
+ } else {
+ pj_assert(!"Invalid comp_id");
+ return -1;
+ }
+
+ return PJ_SUCCESS;
+}
+
+
diff --git a/pjnath/src/pjnath/stun_msg.c b/pjnath/src/pjnath/stun_msg.c
index 058ce833..9b548c52 100644
--- a/pjnath/src/pjnath/stun_msg.c
+++ b/pjnath/src/pjnath/stun_msg.c
@@ -481,7 +481,7 @@ static const struct attr_desc *find_attr_desc(unsigned attr_type)
pj_assert(PJ_ARRAY_SIZE(extended_attr_desc) ==
PJ_STUN_ATTR_END_EXTENDED_ATTR-PJ_STUN_ATTR_START_EXTENDED_ATTR);
- if (attr_type < PJ_STUN_ATTR_START_EXTENDED_ATTR)
+ if (attr_type < PJ_STUN_ATTR_END_MANDATORY_ATTR)
desc = &mandatory_attr_desc[attr_type];
else if (attr_type >= PJ_STUN_ATTR_START_EXTENDED_ATTR &&
attr_type < PJ_STUN_ATTR_END_EXTENDED_ATTR)