summaryrefslogtreecommitdiff
path: root/pjlib-util
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-02-22 02:09:23 +0000
committerBenny Prijono <bennylp@teluu.com>2007-02-22 02:09:23 +0000
commit20968030aa4e9d15c000cca74aa9a3b575c7f41e (patch)
tree972ffc087fc85636daf4caa5d4f2a36f729ac6e7 /pjlib-util
parent1a5b8c19989c4ab4e1eee7f712913f8f3e459e71 (diff)
Continuing work on the new STUN framework, partly implemented the client session
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@993 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjlib-util')
-rw-r--r--pjlib-util/build/pjlib_util.dsp4
-rw-r--r--pjlib-util/build/pjlib_util.dsw18
-rw-r--r--pjlib-util/build/pjstun_client.dsp110
-rw-r--r--pjlib-util/include/pjlib-util/stun_msg.h24
-rw-r--r--pjlib-util/include/pjlib-util/stun_transaction.h36
-rw-r--r--pjlib-util/src/pjlib-util/stun_msg_dump.c208
-rw-r--r--pjlib-util/src/pjlib-util/stun_transaction.c44
-rw-r--r--pjlib-util/src/pjstun-client/client_main.c25
-rw-r--r--pjlib-util/src/pjstun-client/stun_session.c499
-rw-r--r--pjlib-util/src/pjstun-client/stun_session.h114
10 files changed, 1062 insertions, 20 deletions
diff --git a/pjlib-util/build/pjlib_util.dsp b/pjlib-util/build/pjlib_util.dsp
index c24f6342..a4a0e09d 100644
--- a/pjlib-util/build/pjlib_util.dsp
+++ b/pjlib-util/build/pjlib_util.dsp
@@ -137,6 +137,10 @@ SOURCE="..\src\pjlib-util\stun_msg.c"
# End Source File
# Begin Source File
+SOURCE="..\src\pjlib-util\stun_msg_dump.c"
+# End Source File
+# Begin Source File
+
SOURCE="..\src\pjlib-util\stun_server.c"
# End Source File
# Begin Source File
diff --git a/pjlib-util/build/pjlib_util.dsw b/pjlib-util/build/pjlib_util.dsw
index 5831c8c3..519c987a 100644
--- a/pjlib-util/build/pjlib_util.dsw
+++ b/pjlib-util/build/pjlib_util.dsw
@@ -57,6 +57,24 @@ Package=<4>
###############################################################################
+Project: "pjstun_client"=".\pjstun_client.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
+}}}
+
+###############################################################################
+
Project: "pjstun_srv"=".\pjstun_srv.dsp" - Package Owner=<4>
Package=<5>
diff --git a/pjlib-util/build/pjstun_client.dsp b/pjlib-util/build/pjstun_client.dsp
new file mode 100644
index 00000000..b4cbdb3a
--- /dev/null
+++ b/pjlib-util/build/pjstun_client.dsp
@@ -0,0 +1,110 @@
+# Microsoft Developer Studio Project File - Name="pjstun_client" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=pjstun_client - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "pjstun_client.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "pjstun_client.mak" CFG="pjstun_client - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "pjstun_client - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "pjstun_client - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "pjstun_client - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "./output/pjstun-client-i386-win32-vc6-release"
+# PROP BASE Intermediate_Dir "./output/pjstun-client-i386-win32-vc6-release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "./output/pjstun-client-i386-win32-vc6-release"
+# PROP Intermediate_Dir "./output/pjstun-client-i386-win32-vc6-release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../include" /I "../../pjlib/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 netapi32.lib mswsock.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"../bin/pjstun-client-i386-win32-vc6-release.exe"
+
+!ELSEIF "$(CFG)" == "pjstun_client - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "./output/pjstun-client-i386-win32-vc6-debug"
+# PROP BASE Intermediate_Dir "./output/pjstun-client-i386-win32-vc6-debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "./output/pjstun-client-i386-win32-vc6-debug"
+# PROP Intermediate_Dir "./output/pjstun-client-i386-win32-vc6-debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 netapi32.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../bin/pjstun-client-i386-win32-vc6-debug.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "pjstun_client - Win32 Release"
+# Name "pjstun_client - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\src\pjstun-client\client_main.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjstun-client\stun_session.c"
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE="..\src\pjstun-client\stun_session.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/pjlib-util/include/pjlib-util/stun_msg.h b/pjlib-util/include/pjlib-util/stun_msg.h
index e8a4f1af..f5e697f0 100644
--- a/pjlib-util/include/pjlib-util/stun_msg.h
+++ b/pjlib-util/include/pjlib-util/stun_msg.h
@@ -1190,11 +1190,28 @@ PJ_DECL(pj_status_t) pj_stun_msg_encode(const pj_stun_msg *msg,
/**
+ * Dump STUN message to a printable string output.
+ *
+ * @param msg The STUN message
+ * @param buffer Buffer where the printable string output will
+ * be printed on.
+ * @param length On input, specify the maximum length of the buffer.
+ * On output, it will be filled up with the actual
+ * length of the output string.
+ *
+ * @return The message string output.
+ */
+PJ_DECL(char*) pj_stun_msg_dump(const pj_stun_msg *msg,
+ char *buffer,
+ unsigned *length);
+
+
+/**
* Find STUN attribute in the STUN message, starting from the specified
* index.
*
* @param msg The STUN message.
- * @param attr_type The attribute type to be found.
+ * @param attr_type The attribute type to be found, from pj_stun_attr_type.
* @param start_index The start index of the attribute in the message.
* Specify zero to start searching from the first
* attribute.
@@ -1212,7 +1229,7 @@ PJ_DECL(pj_stun_attr_hdr*) pj_stun_msg_find_attr(const pj_stun_msg *msg,
* the port and ip_addr parameters are in host byte order.
*
* @param pool The pool to allocate memory from.
- * @param attr_type Attribute type.
+ * @param attr_type Attribute type, from #pj_stun_attr_type.
* @param xor_ed If non-zero, the port and address will be XOR-ed
* with magic, to make the XOR-MAPPED-ADDRESS attribute.
* @param addr_len Length of \a addr parameter.
@@ -1234,6 +1251,7 @@ pj_stun_generic_ip_addr_attr_create(pj_pool_t *pool,
* Create a STUN generic string attribute.
*
* @param pool The pool to allocate memory from.
+ * @param attr_type Attribute type, from #pj_stun_attr_type.
* @param value The string value to be assigned to the attribute.
* @param p_attr Pointer to receive the attribute.
*
@@ -1315,7 +1333,7 @@ pj_stun_unknown_attr_create(pj_pool_t *pool,
* Create a blank binary attribute.
*
* @param pool The pool to allocate memory from.
- * @param attr_type The attribute type.
+ * @param attr_type The attribute type, from #pj_stun_attr_type.
* @param p_attr Pointer to receive the attribute.
*
* @return PJ_SUCCESS on success or the appropriate error code.
diff --git a/pjlib-util/include/pjlib-util/stun_transaction.h b/pjlib-util/include/pjlib-util/stun_transaction.h
index 2cacef36..ee57d11e 100644
--- a/pjlib-util/include/pjlib-util/stun_transaction.h
+++ b/pjlib-util/include/pjlib-util/stun_transaction.h
@@ -73,7 +73,7 @@ typedef struct pj_stun_tsx_cb
*/
void (*on_complete)(pj_stun_client_tsx *tsx,
pj_status_t status,
- pj_stun_msg *response);
+ const pj_stun_msg *response);
/**
* This callback is called by the STUN transaction when it wants to send
@@ -124,6 +124,16 @@ PJ_DECL(pj_status_t) pj_stun_client_tsx_destroy(pj_stun_client_tsx *tsx);
/**
+ * Check if transaction has completed.
+ *
+ * @param tsx The STUN transaction.
+ *
+ * @return Non-zero if transaction has completed.
+ */
+PJ_DECL(pj_bool_t) pj_stun_client_tsx_is_complete(pj_stun_client_tsx *tsx);
+
+
+/**
* Associate an arbitrary data with the STUN transaction. This data
* can be then retrieved later from the transaction, by using
* pj_stun_client_tsx_get_data() function.
@@ -186,12 +196,34 @@ PJ_DECL(pj_status_t) pj_stun_client_tsx_send_msg(pj_stun_client_tsx *tsx,
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
-PJ_DECL(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx,
+PJ_DECL(pj_status_t) pj_stun_client_tsx_on_rx_pkt(pj_stun_client_tsx *tsx,
const void *packet,
pj_size_t pkt_size,
unsigned *parsed_len);
+/**
+ * Notify the STUN transaction about the arrival of STUN response.
+ * If the STUN response contains a final error (300 and greater), the
+ * transaction will be terminated and callback will be called. If the
+ * STUN response contains response code 100-299, retransmission
+ * will cease, but application must still call this function again
+ * with a final response later to allow the transaction to complete.
+ *
+ * @param tsx The STUN client transaction instance.
+ * @param packet The incoming packet.
+ * @param pkt_size Size of the incoming packet.
+ * @param parsed_len Optional pointer to receive the number of bytes
+ * that have been parsed from the incoming packet
+ * for the STUN message. This is useful if the
+ * STUN transaction is running over stream oriented
+ * socket such as TCP or TLS.
+ *
+ * @return PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx,
+ const pj_stun_msg *msg);
+
/**
* @}
diff --git a/pjlib-util/src/pjlib-util/stun_msg_dump.c b/pjlib-util/src/pjlib-util/stun_msg_dump.c
new file mode 100644
index 00000000..2def62e4
--- /dev/null
+++ b/pjlib-util/src/pjlib-util/stun_msg_dump.c
@@ -0,0 +1,208 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2005 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pjlib-util/stun_msg.h>
+#include <pjlib-util/errno.h>
+#include <pj/assert.h>
+#include <pj/string.h>
+
+
+#define APPLY() if (len < 1 || len >= (end-p)) \
+ goto on_return; \
+ p += len
+
+static int print_attr(char *buffer, unsigned length,
+ const pj_stun_attr_hdr *ahdr)
+{
+ char *p = buffer, *end = buffer + length;
+ int len;
+
+ len = pj_ansi_snprintf(buffer, end-p,
+ " %s: length=%d",
+ pj_stun_get_attr_name(ahdr->type),
+ (int)ahdr->length);
+ APPLY();
+
+
+ switch (ahdr->type) {
+ case PJ_STUN_ATTR_MAPPED_ADDR:
+ case PJ_STUN_ATTR_RESPONSE_ADDR:
+ case PJ_STUN_ATTR_SOURCE_ADDR:
+ case PJ_STUN_ATTR_CHANGED_ADDR:
+ case PJ_STUN_ATTR_REFLECTED_FROM:
+ case PJ_STUN_ATTR_REMOTE_ADDRESS:
+ case PJ_STUN_ATTR_RELAY_ADDRESS:
+ case PJ_STUN_ATTR_XOR_MAPPED_ADDRESS:
+ case PJ_STUN_ATTR_REQUESTED_IP:
+ case PJ_STUN_ATTR_XOR_REFLECTED_FROM:
+ case PJ_STUN_ATTR_XOR_INTERNAL_ADDR:
+ case PJ_STUN_ATTR_ALTERNATE_SERVER:
+ {
+ const pj_stun_generic_ip_addr_attr *attr;
+
+ attr = (const pj_stun_generic_ip_addr_attr*)ahdr;
+
+ if (attr->addr.addr.sa_family == PJ_AF_INET) {
+ len = pj_ansi_snprintf(buffer, end-p,
+ ", IPv4 addr=%s:%d\n",
+ pj_inet_ntoa(attr->addr.ipv4.sin_addr),
+ pj_ntohs(attr->addr.ipv4.sin_port));
+
+ } else if (attr->addr.addr.sa_family == PJ_AF_INET6) {
+ len = pj_ansi_snprintf(buffer, end-p,
+ ", IPv6 addr present\n");
+ } else {
+ len = pj_ansi_snprintf(buffer, end-p,
+ ", INVALID ADDRESS FAMILY!\n");
+ }
+ }
+ break;
+
+ case PJ_STUN_ATTR_CHANGE_REQUEST:
+ case PJ_STUN_ATTR_LIFETIME:
+ case PJ_STUN_ATTR_BANDWIDTH:
+ case PJ_STUN_ATTR_REQUESTED_ADDR_TYPE:
+ case PJ_STUN_ATTR_REQUESTED_PORT_PROPS:
+ case PJ_STUN_ATTR_REQUESTED_TRANSPORT:
+ case PJ_STUN_ATTR_TIMER_VAL:
+ case PJ_STUN_ATTR_PRIORITY:
+ case PJ_STUN_ATTR_FINGERPRINT:
+ case PJ_STUN_ATTR_REFRESH_INTERVAL:
+ {
+ const pj_stun_generic_uint_attr *attr;
+
+ attr = (const pj_stun_generic_uint_attr*)ahdr;
+ len = pj_ansi_snprintf(buffer, end-p,
+ ", value=%d (%x)\n",
+ (pj_uint32_t)attr->value,
+ (pj_uint32_t)attr->value);
+ }
+ break;
+
+ case PJ_STUN_ATTR_USERNAME:
+ case PJ_STUN_ATTR_PASSWORD:
+ case PJ_STUN_ATTR_REALM:
+ case PJ_STUN_ATTR_NONCE:
+ case PJ_STUN_ATTR_SERVER:
+ {
+ const pj_stun_generic_string_attr *attr;
+
+ attr = (pj_stun_generic_string_attr*)ahdr;
+ len = pj_ansi_snprintf(buffer, end-p,
+ ", value=\"%.*s\"\n",
+ (int)attr->value.slen,
+ attr->value.ptr);
+ }
+ break;
+
+ case PJ_STUN_ATTR_ERROR_CODE:
+ {
+ const pj_stun_error_code_attr *attr;
+
+ attr = (const pj_stun_error_code_attr*) ahdr;
+ len = pj_ansi_snprintf(buffer, end-p,
+ ", err_code=%d, reason=\"%.*s\"\n",
+ attr->err_class*100 + attr->number,
+ (int)attr->reason.slen,
+ attr->reason.ptr);
+ }
+ break;
+
+ case PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES:
+ {
+ const pj_stun_unknown_attr *attr;
+ unsigned j;
+
+ attr = (const pj_stun_unknown_attr*) ahdr;
+
+ len = pj_ansi_snprintf(buffer, end-p,
+ ", unknown list:");
+ APPLY();
+
+ for (j=0; j<attr->attr_count; ++j) {
+ len = pj_ansi_snprintf(buffer, end-p,
+ " %d",
+ (int)attr->attrs[j]);
+ APPLY();
+ }
+ }
+ break;
+
+ case PJ_STUN_ATTR_MESSAGE_INTEGRITY:
+ case PJ_STUN_ATTR_DATA:
+ case PJ_STUN_ATTR_USE_CANDIDATE:
+ default:
+ len = pj_ansi_snprintf(buffer, end-p, "\n");
+
+ break;
+ }
+
+ APPLY();
+
+ return (p-buffer);
+
+on_return:
+ return len;
+}
+
+
+/*
+ * Dump STUN message to a printable string output.
+ */
+PJ_DEF(char*) pj_stun_msg_dump(const pj_stun_msg *msg,
+ char *buffer,
+ unsigned *length)
+{
+ char *p, *end;
+ int len;
+ unsigned i;
+
+ PJ_ASSERT_RETURN(msg && buffer && length, NULL);
+
+ p = buffer;
+ end = buffer + (*length);
+
+ len = pj_ansi_snprintf(p, end-p, "STUN %s %s\n",
+ pj_stun_get_method_name(msg->hdr.type),
+ pj_stun_get_class_name(msg->hdr.type));
+ APPLY();
+
+ len = pj_ansi_snprintf(p, end-p,
+ " Hdr: length=%d, magic=%x, tsx_id=%x %x %x\n"
+ " Attributes:\n",
+ msg->hdr.length,
+ msg->hdr.magic,
+ *(pj_uint32_t*)&msg->hdr.tsx_id[0],
+ *(pj_uint32_t*)&msg->hdr.tsx_id[4],
+ *(pj_uint32_t*)&msg->hdr.tsx_id[8]);
+ APPLY();
+
+ for (i=0; i<msg->attr_count; ++i) {
+ len = print_attr(p, end-p, msg->attr[i]);
+ APPLY();
+ }
+
+on_return:
+ *p = '\0';
+ *length = (p-buffer);
+ return buffer;
+
+}
+
+
+#undef APPLY
diff --git a/pjlib-util/src/pjlib-util/stun_transaction.c b/pjlib-util/src/pjlib-util/stun_transaction.c
index 6720b8d7..701122fe 100644
--- a/pjlib-util/src/pjlib-util/stun_transaction.c
+++ b/pjlib-util/src/pjlib-util/stun_transaction.c
@@ -252,29 +252,16 @@ static void retransmit_timer_callback(pj_timer_heap_t *timer_heap,
}
+
/*
* Notify the STUN transaction about the arrival of STUN response.
*/
PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx,
- const void *packet,
- pj_size_t pkt_size,
- unsigned *parsed_len)
+ const pj_stun_msg *msg)
{
- pj_stun_msg *msg;
pj_stun_error_code_attr *err_attr;
pj_status_t status;
- PJ_ASSERT_RETURN(tsx && packet && pkt_size, PJ_EINVAL);
-
- /* Try to parse the message */
- status = pj_stun_msg_decode(tsx->pool, (const pj_uint8_t*)packet,
- pkt_size, 0, &msg, parsed_len,
- NULL, NULL, NULL);
- if (status != PJ_SUCCESS) {
- stun_perror(tsx, "STUN msg_decode() error", status);
- return status;
- }
-
/* Must be STUN response message */
if (!PJ_STUN_IS_RESPONSE(msg->hdr.type) &&
!PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))
@@ -329,5 +316,32 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx,
}
return PJ_SUCCESS;
+
+}
+
+
+/*
+ * Notify the STUN transaction about the arrival of STUN response.
+ */
+PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_pkt(pj_stun_client_tsx *tsx,
+ const void *packet,
+ pj_size_t pkt_size,
+ unsigned *parsed_len)
+{
+ pj_stun_msg *msg;
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(tsx && packet && pkt_size, PJ_EINVAL);
+
+ /* Try to parse the message */
+ status = pj_stun_msg_decode(tsx->pool, (const pj_uint8_t*)packet,
+ pkt_size, 0, &msg, parsed_len,
+ NULL, NULL, NULL);
+ if (status != PJ_SUCCESS) {
+ stun_perror(tsx, "STUN msg_decode() error", status);
+ return status;
+ }
+
+ return pj_stun_client_tsx_on_rx_msg(tsx, msg);
}
diff --git a/pjlib-util/src/pjstun-client/client_main.c b/pjlib-util/src/pjstun-client/client_main.c
new file mode 100644
index 00000000..7dc0540d
--- /dev/null
+++ b/pjlib-util/src/pjstun-client/client_main.c
@@ -0,0 +1,25 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2005 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pjlib-util.h>
+#include <pjlib.h>
+
+
+#define THIS_FILE "client_main.c"
+#define MAX_THREADS 8
+
diff --git a/pjlib-util/src/pjstun-client/stun_session.c b/pjlib-util/src/pjstun-client/stun_session.c
new file mode 100644
index 00000000..571b723d
--- /dev/null
+++ b/pjlib-util/src/pjstun-client/stun_session.c
@@ -0,0 +1,499 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2005 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 "stun_session.h"
+#include <pjlib.h>
+
+struct pj_stun_session
+{
+ pj_stun_endpoint *endpt;
+ pj_pool_t *pool;
+ pj_stun_session_cb cb;
+ void *user_data;
+
+ pj_str_t realm;
+ pj_str_t username;
+ pj_str_t password;
+
+ pj_bool_t fingerprint_enabled;
+
+ pj_stun_tx_data pending_request_list;
+};
+
+#define SNAME(s_) ((s_)->pool->obj_name)
+
+#if PJ_LOG_MAX_LEVEL >= 5
+# define TRACE_(expr) PJ_LOG(5,expr)
+#else
+# define TRACE_(expr)
+#endif
+
+#if PJ_LOG_MAX_LEVEL >= 4
+# define LOG_ERR_(sess, title, rc)
+static void stun_perror(pj_stun_session *sess, const char *title,
+ pj_status_t status)
+{
+ char errmsg[PJ_ERR_MSG_SIZE];
+
+ pj_strerror(status, errmsg, sizeof(errmsg));
+
+ PJ_LOG(4,(SNAME(sess), "%s: %s", title, errmsg));
+}
+
+#else
+# define ERR_(sess, title, rc)
+#endif
+
+#define TDATA_POOL_SIZE 1024
+#define TDATA_POOL_INC 1024
+
+
+static void tsx_on_complete(pj_stun_client_tsx *tsx,
+ pj_status_t status,
+ const pj_stun_msg *response);
+static pj_status_t tsx_on_send_msg(pj_stun_client_tsx *tsx,
+ const void *stun_pkt,
+ pj_size_t pkt_size);
+
+static pj_stun_tsx_cb tsx_cb =
+{
+ &tsx_on_complete,
+ &tsx_on_send_msg
+};
+
+
+static pj_status_t tsx_add(pj_stun_session *sess,
+ pj_stun_tx_data *tdata)
+{
+ pj_list_push_back(&sess->pending_request_list, tdata);
+ return PJ_SUCCESS;
+}
+
+static pj_status_t tsx_erase(pj_stun_session *sess,
+ pj_stun_tx_data *tdata)
+{
+ pj_list_erase(tdata);
+ return PJ_SUCCESS;
+}
+
+static pj_stun_tx_data* tsx_lookup(pj_stun_session *sess,
+ const pj_stun_msg *msg)
+{
+ pj_stun_tx_data *tdata;
+
+ tdata = sess->pending_request_list.next;
+ while (tdata != &sess->pending_request_list) {
+ pj_assert(sizeof(tdata->client_key)==sizeof(msg->hdr.tsx_id));
+ if (pj_memcmp(tdata->client_key, msg->hdr.tsx_id,
+ sizeof(msg->hdr.tsx_id))==0)
+ {
+ return tdata;
+ }
+ tdata = tdata->next;
+ }
+
+ return NULL;
+}
+
+static pj_status_t create_tdata(pj_stun_session *sess,
+ unsigned msg_type,
+ void *user_data,
+ pj_stun_tx_data **p_tdata)
+{
+ pj_pool_t *pool;
+ pj_status_t status;
+ pj_stun_tx_data *tdata;
+
+ /* Create pool and initialize basic tdata attributes */
+ pool = pj_pool_create(sess->endpt->pf, "tdata%p",
+ TDATA_POOL_SIZE, TDATA_POOL_INC, NULL);
+ PJ_ASSERT_RETURN(pool, PJ_ENOMEM);
+
+ tdata = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_tx_data);
+ tdata->pool = pool;
+ tdata->sess = sess;
+ tdata->user_data = tdata;
+
+ /* Create STUN message */
+ status = pj_stun_msg_create(pool, msg_type, PJ_STUN_MAGIC,
+ NULL, &tdata->msg);
+ if (status != PJ_SUCCESS) {
+ pj_pool_release(pool);
+ return status;
+ }
+
+ /* If this is a request, then copy the request's transaction ID
+ * as the transaction key.
+ */
+ if (PJ_STUN_IS_REQUEST(msg_type)) {
+ pj_assert(sizeof(tdata->client_key)==sizeof(tdata->msg->hdr.tsx_id));
+ pj_memcpy(tdata->client_key, tdata->msg->hdr.tsx_id,
+ sizeof(tdata->msg->hdr.tsx_id));
+ }
+
+ *p_tdata = tdata;
+
+ return PJ_SUCCESS;
+}
+
+static void destroy_tdata(pj_stun_tx_data *tdata)
+{
+ if (tdata->client_tsx) {
+ tsx_erase(tdata->sess, tdata);
+ pj_stun_client_tsx_destroy(tdata->client_tsx);
+ tdata->client_tsx = NULL;
+ }
+
+ pj_pool_release(tdata->pool);
+}
+
+static pj_status_t session_apply_req(pj_stun_session *sess,
+ pj_pool_t *pool,
+ pj_stun_msg *msg)
+{
+ pj_status_t status;
+
+ /* From draft-ietf-behave-rfc3489bis-05.txt
+ * Section 8.3.1. Formulating the Request Message
+ */
+ if (sess->realm.slen || sess->username.slen) {
+ pj_stun_generic_string_attr *auname;
+ pj_stun_msg_integrity_attr *amsgi;
+
+ /* Create and add USERNAME attribute */
+ status = pj_stun_generic_string_attr_create(sess->pool,
+ PJ_STUN_ATTR_USERNAME,
+ &sess->username,
+ &auname);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+
+ status = pj_stun_msg_add_attr(msg, &auname->hdr);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+
+ if (sess->realm.slen) {
+ /* Add REALM only when long term credential is used */
+ pj_stun_generic_string_attr *arealm;
+ status = pj_stun_generic_string_attr_create(sess->pool,
+ PJ_STUN_ATTR_REALM,
+ &sess->realm,
+ &arealm);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+
+ status = pj_stun_msg_add_attr(msg, &arealm->hdr);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+ }
+
+ /* Add MESSAGE-INTEGRITY attribute */
+ status = pj_stun_msg_integrity_attr_create(sess->pool, &amsgi);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+
+ status = pj_stun_msg_add_attr(msg, &amsgi->hdr);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+
+ PJ_TODO(COMPUTE_MESSAGE_INTEGRITY);
+
+ }
+
+ /* Add FINGERPRINT attribute if necessary */
+ if (sess->fingerprint_enabled) {
+ pj_stun_fingerprint_attr *af;
+
+ status = pj_stun_generic_uint_attr_create(sess->pool,
+ PJ_STUN_ATTR_FINGERPRINT,
+ 0, &af);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+
+ status = pj_stun_msg_add_attr(msg, &af->hdr);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+ }
+
+ return PJ_SUCCESS;
+}
+
+
+
+
+
+
+PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_endpoint *endpt,
+ const char *name,
+ const pj_stun_session_cb *cb,
+ pj_stun_session **p_sess)
+{
+ pj_pool_t *pool;
+ pj_stun_session *sess;
+
+ PJ_ASSERT_RETURN(endpt && cb && p_sess, PJ_EINVAL);
+
+ pool = pj_pool_create(endpt->pf, name, 4000, 4000, NULL);
+ PJ_ASSERT_RETURN(pool, PJ_ENOMEM);
+
+ sess = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_session);
+ sess->endpt = endpt;
+ sess->pool = pool;
+ pj_memcpy(&sess->cb, cb, sizeof(*cb));
+
+ pj_list_init(&sess->pending_request_list);
+
+ *p_sess = sess;
+
+ PJ_TODO(MUTEX_PROTECTION);
+
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess)
+{
+ PJ_ASSERT_RETURN(sess, PJ_EINVAL);
+ pj_pool_release(sess->pool);
+
+ return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pj_stun_session_set_user_data( pj_stun_session *sess,
+ void *user_data)
+{
+ PJ_ASSERT_RETURN(sess, PJ_EINVAL);
+ sess->user_data = user_data;
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(void*) pj_stun_session_get_user_data(pj_stun_session *sess)
+{
+ PJ_ASSERT_RETURN(sess, NULL);
+ return sess->user_data;
+}
+
+PJ_DEF(pj_status_t) pj_stun_session_set_credential( pj_stun_session *sess,
+ const pj_str_t *realm,
+ const pj_str_t *user,
+ const pj_str_t *passwd)
+{
+ pj_str_t empty = { NULL, 0 };
+
+ PJ_ASSERT_RETURN(sess, PJ_EINVAL);
+ pj_strdup_with_null(sess->pool, &sess->realm, realm ? realm : &empty);
+ pj_strdup_with_null(sess->pool, &sess->username, user ? user : &empty);
+ pj_strdup_with_null(sess->pool, &sess->password, passwd ? passwd : &empty);
+
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_stun_session_enable_fingerprint(pj_stun_session *sess,
+ pj_bool_t enabled)
+{
+ PJ_ASSERT_RETURN(sess, PJ_EINVAL);
+ sess->fingerprint_enabled = enabled;
+ return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pj_stun_session_create_bind_req(pj_stun_session *sess,
+ pj_stun_tx_data **p_tdata)
+{
+ pj_pool_t *pool;
+ pj_stun_tx_data *tdata;
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(sess && p_tdata, PJ_EINVAL);
+
+ status = create_tdata(sess, PJ_STUN_BINDING_REQUEST, NULL, &tdata);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ status = session_apply_req(sess, pool, tdata->msg);
+ if (status != PJ_SUCCESS) {
+ destroy_tdata(tdata);
+ return status;
+ }
+
+ *p_tdata = tdata;
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_stun_session_create_allocate_req(pj_stun_session *sess,
+ pj_stun_tx_data **p_tdata)
+{
+ PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP);
+}
+
+
+PJ_DEF(pj_status_t)
+pj_stun_session_create_set_active_destination_req(pj_stun_session *sess,
+ pj_stun_tx_data **p_tdata)
+{
+ PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP);
+}
+
+PJ_DEF(pj_status_t) pj_stun_session_create_connect_req( pj_stun_session *sess,
+ pj_stun_tx_data **p_tdata)
+{
+ PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP);
+}
+
+PJ_DEF(pj_status_t)
+pj_stun_session_create_connection_status_ind(pj_stun_session *sess,
+ pj_stun_tx_data **p_tdata)
+{
+ PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP);
+}
+
+PJ_DEF(pj_status_t) pj_stun_session_create_send_ind( pj_stun_session *sess,
+ pj_stun_tx_data **p_tdata)
+{
+ PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP);
+}
+
+PJ_DEF(pj_status_t) pj_stun_session_create_data_ind( pj_stun_session *sess,
+ pj_stun_tx_data **p_tdata)
+{
+ PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP);
+}
+
+PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
+ unsigned addr_len,
+ const pj_sockaddr_t *server,
+ pj_stun_tx_data *tdata)
+{
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(sess && addr_len && server && tdata, PJ_EINVAL);
+
+ if (PJ_LOG_MAX_LEVEL >= 5) {
+ char buf[512];
+ unsigned buflen = sizeof(buf);
+ const char *dst_name;
+ int dst_port;
+ const pj_sockaddr *dst = (const pj_sockaddr*)server;
+
+ if (dst->sa_family == PJ_AF_INET) {
+ const pj_sockaddr_in *dst4 = (const pj_sockaddr_in*)dst;
+ dst_name = pj_inet_ntoa(dst4->sin_addr);
+ dst_port = pj_ntohs(dst4->sin_port);
+ } else if (dst->sa_family == PJ_AF_INET6) {
+ const pj_sockaddr_in6 *dst6 = (const pj_sockaddr_in6*)dst;
+ dst_name = "IPv6";
+ dst_port = pj_ntohs(dst6->sin6_port);
+ } else {
+ LOG_ERR_(sess, "Invalid address family", PJ_EINVAL);
+ return PJ_EINVAL;
+ }
+
+ PJ_LOG(5,(SNAME(sess),
+ "Sending STUN message to %s:%d:\n"
+ "%s\n",
+ dst_name, dst_port,
+ pj_stun_msg_dump(tdata->msg, buf, &buflen)));
+ }
+
+
+ /* If this is a STUN request message, then send the request with
+ * a new STUN client transaction.
+ */
+ if (PJ_STUN_IS_REQUEST(tdata->msg->hdr.type)) {
+
+ /* Create STUN client transaction */
+ status = pj_stun_client_tsx_create(sess->endpt, &tsx_cb,
+ &tdata->client_tsx);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+ pj_stun_client_tsx_set_data(tdata->client_tsx, (void*)tdata);
+
+ /* Send the request! */
+ status = pj_stun_client_tsx_send_msg(tdata->client_tsx, PJ_TRUE,
+ tdata->msg);
+ if (status != PJ_SUCCESS && status != PJ_EPENDING) {
+ LOG_ERR_(sess, "Error sending STUN request", status);
+ return status;
+ }
+
+ /* Add to pending request list */
+ tsx_add(sess, tdata);
+
+ } else {
+ /* Otherwise for non-request message, send directly to transport. */
+ status = sess->cb.on_send_msg(tdata, addr_len, server);
+ }
+
+
+ return status;
+}
+
+
+PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
+ const void *packet,
+ pj_size_t pkt_size,
+ unsigned *parsed_len)
+{
+ pj_stun_msg *msg;
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(sess && packet && pkt_size, PJ_EINVAL);
+
+ /* Try to parse the message */
+ status = pj_stun_msg_decode(tsx->pool, (const pj_uint8_t*)packet,
+ pkt_size, 0, &msg, parsed_len,
+ NULL, NULL, NULL);
+ if (status != PJ_SUCCESS) {
+ LOG_ERR_(sess, "STUN msg_decode() error", status);
+ return status;
+ }
+
+ if (PJ_STUN_IS_RESPONSE(msg->hdr.type) ||
+ PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))
+ {
+ pj_stun_tx_data *tdata;
+
+ /* Lookup pending client transaction */
+ tdata = tsx_lookup(sess, msg);
+ if (tdata == NULL) {
+ LOG_ERR_(sess, "STUN error finding transaction", PJ_ENOTFOUND);
+ return PJ_ENOTFOUND;
+ }
+
+ /* Pass the response to the transaction.
+ * If the message is accepted, transaction callback will be called,
+ * and this will call the session callback too.
+ */
+ status = pj_stun_client_tsx_on_rx_msg(tdata->client_tsx, msg);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* If transaction has completed, destroy the transmit data.
+ * This will remove the transaction from the pending list too.
+ */
+ if (pj_stun_client_tsx_is_complete(tdata->client_tsx)) {
+ destroy_tdata(tdata);
+ tdata = NULL;
+ }
+
+ return PJ_SUCCESS;
+
+ } else if (PJ_STUN_IS_REQUEST(msg->hdr.type)) {
+
+
+ } else if (PJ_STUN_IS_INDICATION(msg->hdr.type)) {
+
+
+ } else {
+ pj_assert(!"Unexpected!");
+ return PJ_EBUG;
+ }
+
+}
+
diff --git a/pjlib-util/src/pjstun-client/stun_session.h b/pjlib-util/src/pjstun-client/stun_session.h
new file mode 100644
index 00000000..f9759cb9
--- /dev/null
+++ b/pjlib-util/src/pjstun-client/stun_session.h
@@ -0,0 +1,114 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2005 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __PJLIB_UTIL_STUN_SESSION_H__
+#define __PJLIB_UTIL_STUN_SESSION_H__
+
+#include <pjlib-util/stun_msg.h>
+#include <pjlib-util/stun_endpoint.h>
+#include <pjlib-util/stun_transaction.h>
+#include <pj/list.h>
+
+
+typedef struct pj_stun_tx_data pj_stun_tx_data;
+typedef struct pj_stun_session pj_stun_session;
+
+typedef struct pj_stun_session_cb
+{
+ pj_status_t (*on_send_msg)(pj_stun_tx_data *tdata,
+ unsigned addr_len,
+ const pj_sockaddr_t *dst_addr);
+
+ void (*on_bind_response)(void *user_data, pj_status_t status, pj_stun_msg *response);
+ void (*on_allocate_response)(void *user_data, pj_status_t status, pj_stun_msg *response);
+ void (*on_set_active_destination_response)(void *user_data, pj_status_t status, pj_stun_msg *response);
+ void (*on_connect_response)(void *user_data, pj_status_t status, pj_stun_msg *response);
+} pj_stun_session_cb;
+
+
+struct pj_stun_tx_data
+{
+ PJ_DECL_LIST_MEMBER(struct pj_stun_tx_data);
+
+ pj_pool_t *pool;
+ pj_stun_session *sess;
+ pj_stun_msg *msg;
+ void *user_data;
+
+ pj_stun_client_tsx *client_tsx;
+ pj_uint8_t client_key[12];
+};
+
+
+PJ_DECL(pj_status_t) pj_stun_session_create(pj_stun_endpoint *endpt,
+ const char *name,
+ const pj_stun_session_cb *cb,
+ pj_stun_session **p_sess);
+
+PJ_DECL(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess);
+
+PJ_DECL(pj_status_t) pj_stun_session_set_user_data(pj_stun_session *sess,
+ void *user_data);
+
+PJ_DECL(void*) pj_stun_session_get_user_data(pj_stun_session *sess);
+
+PJ_DECL(pj_status_t) pj_stun_session_set_credential(pj_stun_session *sess,
+ const pj_str_t *realm,
+ const pj_str_t *user,
+ const pj_str_t *passwd);
+
+PJ_DECL(pj_status_t) pj_stun_session_enable_fingerprint(pj_stun_session *sess,
+ pj_bool_t enabled);
+
+PJ_DECL(pj_status_t) pj_stun_session_create_bind_req(pj_stun_session *sess,
+ pj_stun_tx_data **p_tdata);
+
+PJ_DECL(pj_status_t) pj_stun_session_create_allocate_req(pj_stun_session *sess,
+ pj_stun_tx_data **p_tdata);
+
+PJ_DECL(pj_status_t)
+pj_stun_session_create_set_active_destination_req(pj_stun_session *sess,
+ pj_stun_tx_data **p_tdata);
+
+PJ_DECL(pj_status_t) pj_stun_session_create_connect_req(pj_stun_session *sess,
+ pj_stun_tx_data **p_tdata);
+
+PJ_DECL(pj_status_t)
+pj_stun_session_create_connection_status_ind(pj_stun_session *sess,
+ pj_stun_tx_data **p_tdata);
+
+PJ_DECL(pj_status_t) pj_stun_session_create_send_ind(pj_stun_session *sess,
+ pj_stun_tx_data **p_tdata);
+
+PJ_DECL(pj_status_t) pj_stun_session_create_data_ind(pj_stun_session *sess,
+ pj_stun_tx_data **p_tdata);
+
+PJ_DECL(pj_status_t) pj_stun_session_send_msg(pj_stun_session *sess,
+ unsigned addr_len,
+ const pj_sockaddr_t *server,
+ pj_stun_tx_data *tdata);
+
+PJ_DECL(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
+ const void *packet,
+ pj_size_t pkt_size,
+ unsigned *parsed_len);
+
+
+
+#endif /* __PJLIB_UTIL_STUN_SESSION_H__ */
+