summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pjlib-util/build/pjlib_util.dsp16
-rw-r--r--pjlib-util/build/pjlib_util.vcproj12
-rw-r--r--pjlib-util/build/pjstun_srv_test.dsp4
-rw-r--r--pjlib-util/include/pjlib-util.h2
-rw-r--r--pjlib-util/include/pjlib-util/errno.h46
-rw-r--r--pjlib-util/include/pjlib-util/stun_auth.h275
-rw-r--r--pjlib-util/include/pjlib-util/stun_msg.h364
-rw-r--r--pjlib-util/include/pjlib-util/stun_server.h109
-rw-r--r--pjlib-util/include/pjlib-util/stun_session.h91
-rw-r--r--pjlib-util/src/pjlib-util/errno.c17
-rw-r--r--pjlib-util/src/pjlib-util/stun_auth.c341
-rw-r--r--pjlib-util/src/pjlib-util/stun_msg.c741
-rw-r--r--pjlib-util/src/pjlib-util/stun_msg_dump.c16
-rw-r--r--pjlib-util/src/pjlib-util/stun_server.c129
-rw-r--r--pjlib-util/src/pjlib-util/stun_session.c334
-rw-r--r--pjlib-util/src/pjlib-util/stun_transaction.c7
-rw-r--r--pjlib-util/src/pjstun-client/client_main.c51
-rw-r--r--pjlib-util/src/pjstun-srv-test/server_main.c108
18 files changed, 1379 insertions, 1284 deletions
diff --git a/pjlib-util/build/pjlib_util.dsp b/pjlib-util/build/pjlib_util.dsp
index 6aa10d11..84d30b98 100644
--- a/pjlib-util/build/pjlib_util.dsp
+++ b/pjlib-util/build/pjlib_util.dsp
@@ -145,19 +145,19 @@ SOURCE="..\src\pjlib-util\string.c"
# End Source File
# Begin Source File
-SOURCE="..\src\pjlib-util\stun_endpoint.c"
+SOURCE="..\src\pjlib-util\stun_auth.c"
# End Source File
# Begin Source File
-SOURCE="..\src\pjlib-util\stun_msg.c"
+SOURCE="..\src\pjlib-util\stun_endpoint.c"
# End Source File
# Begin Source File
-SOURCE="..\src\pjlib-util\stun_msg_dump.c"
+SOURCE="..\src\pjlib-util\stun_msg.c"
# End Source File
# Begin Source File
-SOURCE="..\src\pjlib-util\stun_server.c"
+SOURCE="..\src\pjlib-util\stun_msg_dump.c"
# End Source File
# Begin Source File
@@ -249,19 +249,19 @@ SOURCE="..\include\pjlib-util\string.h"
# End Source File
# Begin Source File
-SOURCE="..\include\pjlib-util\stun_doc.h"
+SOURCE="..\include\pjlib-util\stun_auth.h"
# End Source File
# Begin Source File
-SOURCE="..\include\pjlib-util\stun_endpoint.h"
+SOURCE="..\include\pjlib-util\stun_doc.h"
# End Source File
# Begin Source File
-SOURCE="..\include\pjlib-util\stun_msg.h"
+SOURCE="..\include\pjlib-util\stun_endpoint.h"
# End Source File
# Begin Source File
-SOURCE="..\include\pjlib-util\stun_server.h"
+SOURCE="..\include\pjlib-util\stun_msg.h"
# End Source File
# Begin Source File
diff --git a/pjlib-util/build/pjlib_util.vcproj b/pjlib-util/build/pjlib_util.vcproj
index d07f073d..53a9e617 100644
--- a/pjlib-util/build/pjlib_util.vcproj
+++ b/pjlib-util/build/pjlib_util.vcproj
@@ -415,6 +415,10 @@
</FileConfiguration>
</File>
<File
+ RelativePath="..\src\pjlib-util\stun_auth.c"
+ >
+ </File>
+ <File
RelativePath="..\src\pjlib-util\stun_endpoint.c"
>
</File>
@@ -427,7 +431,7 @@
>
</File>
<File
- RelativePath="..\src\pjlib-util\stun_server.c"
+ RelativePath="..\src\pjlib-util\stun_session.c"
>
</File>
<File
@@ -552,6 +556,10 @@
>
</File>
<File
+ RelativePath="..\include\pjlib-util\stun_auth.h"
+ >
+ </File>
+ <File
RelativePath="..\include\pjlib-util\stun_doc.h"
>
</File>
@@ -564,7 +572,7 @@
>
</File>
<File
- RelativePath="..\include\pjlib-util\stun_server.h"
+ RelativePath="..\include\pjlib-util\stun_session.h"
>
</File>
<File
diff --git a/pjlib-util/build/pjstun_srv_test.dsp b/pjlib-util/build/pjstun_srv_test.dsp
index 227a3405..f9a8ff9d 100644
--- a/pjlib-util/build/pjstun_srv_test.dsp
+++ b/pjlib-util/build/pjstun_srv_test.dsp
@@ -93,10 +93,6 @@ SOURCE="..\src\pjstun-srv-test\server_main.c"
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE="..\src\pjstun-srv-test\server.h"
-# End Source File
# End Group
# Begin Group "Resource Files"
diff --git a/pjlib-util/include/pjlib-util.h b/pjlib-util/include/pjlib-util.h
index 7c8e2ad4..6c4f871a 100644
--- a/pjlib-util/include/pjlib-util.h
+++ b/pjlib-util/include/pjlib-util.h
@@ -49,9 +49,9 @@
#include <pjlib-util/xml.h>
/* New STUN */
+#include <pjlib-util/stun_auth.h>
#include <pjlib-util/stun_endpoint.h>
#include <pjlib-util/stun_msg.h>
-#include <pjlib-util/stun_server.h>
#include <pjlib-util/stun_session.h>
#include <pjlib-util/stun_transaction.h>
diff --git a/pjlib-util/include/pjlib-util/errno.h b/pjlib-util/include/pjlib-util/errno.h
index d33ed1a2..bff14194 100644
--- a/pjlib-util/include/pjlib-util/errno.h
+++ b/pjlib-util/include/pjlib-util/errno.h
@@ -261,24 +261,20 @@
/* Messaging errors */
/**
* @hideinitializer
- * Invalid STUN attribute
- */
-#define PJLIB_UTIL_ESTUNINATTR (PJLIB_UTIL_ERRNO_START+110)/* 320110 */
-/**
- * @hideinitializer
* Too many STUN attributes.
*/
-#define PJLIB_UTIL_ESTUNTOOMANYATTR (PJLIB_UTIL_ERRNO_START+111)/* 320111 */
+#define PJLIB_UTIL_ESTUNTOOMANYATTR (PJLIB_UTIL_ERRNO_START+110)/* 320110 */
/**
* @hideinitializer
- * Unknown STUN attribute.
+ * Unknown STUN attribute. This error happens when the decoder encounters
+ * mandatory attribute type which it doesn't understand.
*/
-#define PJLIB_UTIL_ESTUNUNKNOWNATTR (PJLIB_UTIL_ERRNO_START+112)/* 320112 */
+#define PJLIB_UTIL_ESTUNUNKNOWNATTR (PJLIB_UTIL_ERRNO_START+111)/* 320111 */
/**
* @hideinitializer
* Invalid STUN socket address length.
*/
-#define PJLIB_UTIL_ESTUNINADDRLEN (PJLIB_UTIL_ERRNO_START+113)/* 320113 */
+#define PJLIB_UTIL_ESTUNINADDRLEN (PJLIB_UTIL_ERRNO_START+112)/* 320112 */
/**
* @hideinitializer
* STUN IPv6 attribute not supported
@@ -319,9 +315,39 @@
* present), the USERNAME attribute must be present in the message.
*/
#define PJLIB_UTIL_ESTUNNOUSERNAME (PJLIB_UTIL_ERRNO_START+120)/* 320120 */
+/**
+ * @hideinitializer
+ * Unknown STUN username/credential.
+ */
+#define PJLIB_UTIL_ESTUNUSERNAME (PJLIB_UTIL_ERRNO_START+121)/* 320121 */
+/**
+ * @hideinitializer
+ * Missing/invalidSTUN MESSAGE-INTEGRITY attribute.
+ */
+#define PJLIB_UTIL_ESTUNMSGINT (PJLIB_UTIL_ERRNO_START+122)/* 320122 */
+/**
+ * @hideinitializer
+ * Found duplicate STUN attribute.
+ */
+#define PJLIB_UTIL_ESTUNDUPATTR (PJLIB_UTIL_ERRNO_START+123)/* 320123 */
+/**
+ * @hideinitializer
+ * Missing STUN REALM attribute.
+ */
+#define PJLIB_UTIL_ESTUNNOREALM (PJLIB_UTIL_ERRNO_START+124)/* 320124 */
+/**
+ * @hideinitializer
+ * Missing/stale STUN NONCE attribute value.
+ */
+#define PJLIB_UTIL_ESTUNNONCE (PJLIB_UTIL_ERRNO_START+125)/* 320125 */
+/**
+ * @hideinitializer
+ * STUN transaction terminates with failure.
+ */
+#define PJLIB_UTIL_ESTUNTSXFAILED (PJLIB_UTIL_ERRNO_START+126)/* 320126 */
-#define PJ_STATUS_FROM_STUN_CODE(code) (PJLIB_UTIL_ERRNO_START+code)
+//#define PJ_STATUS_FROM_STUN_CODE(code) (PJLIB_UTIL_ERRNO_START+code)
diff --git a/pjlib-util/include/pjlib-util/stun_auth.h b/pjlib-util/include/pjlib-util/stun_auth.h
new file mode 100644
index 00000000..2e0f81ee
--- /dev/null
+++ b/pjlib-util/include/pjlib-util/stun_auth.h
@@ -0,0 +1,275 @@
+/* $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 __PJ_STUN_AUTH_H__
+#define __PJ_STUN_AUTH_H__
+
+/**
+ * @file stun_auth.h
+ * @brief STUN authentication.
+ */
+
+#include <pjlib-util/stun_msg.h>
+
+
+PJ_BEGIN_DECL
+
+
+/* **************************************************************************/
+/**
+ * @defgroup PJLIB_UTIL_STUN_AUTH STUN Authentication
+ * @ingroup PJLIB_UTIL_STUN
+ * @{
+ */
+
+/**
+ * Type of authentication data in the credential.
+ */
+typedef enum pj_stun_auth_cred_type
+{
+ /**
+ * The credential data contains a static credential to be matched
+ * against the credential in the message. A static credential can be
+ * used as both client side or server side authentication.
+ */
+ PJ_STUN_AUTH_CRED_STATIC,
+
+ /**
+ * The credential data contains callbacks to be called to verify the
+ * credential in the message. A dynamic credential is suitable when
+ * performing server side authentication where server does not know
+ * in advance the identity of the user requesting authentication.
+ */
+ PJ_STUN_AUTH_CRED_DYNAMIC
+
+} pj_stun_auth_cred_type;
+
+
+/**
+ * This structure contains the descriptions needed to perform server side
+ * authentication. Depending on the \a type set in the structure, application
+ * may specify a static username/password combination, or to have callbacks
+ * called by the function to authenticate the credential dynamically.
+ */
+typedef struct pj_stun_auth_cred
+{
+ /**
+ * The type of authentication information in this structure.
+ */
+ pj_stun_auth_cred_type type;
+
+ /**
+ * This union contains the authentication data.
+ */
+ union
+ {
+ /**
+ * This structure contains static data for performing authentication.
+ * A non-empty realm indicates whether short term or long term
+ * credential is used.
+ */
+ struct
+ {
+ /**
+ * If not-empty, it indicates that this is a long term credential.
+ */
+ pj_str_t realm;
+
+ /**
+ * The username of the credential.
+ */
+ pj_str_t username;
+
+ /**
+ * Data type to indicate the type of password in the \a data field.
+ * Value zero indicates that the data contains a plaintext
+ * password.
+ */
+ int data_type;
+
+ /**
+ * The data, which depends depends on the value of \a data_type
+ * field. When \a data_type is zero, this field will contain the
+ * plaintext password.
+ */
+ pj_str_t data;
+
+ /**
+ * Optional NONCE.
+ */
+ pj_str_t nonce;
+
+ } static_cred;
+
+ /**
+ * This structure contains callback to be called by the framework
+ * to authenticate the incoming message.
+ */
+ struct
+ {
+ /**
+ * User data which will be passed back to callback functions.
+ */
+ void *user_data;
+
+ /**
+ * This callback is called by pj_stun_verify_credential() when
+ * server needs to challenge the request with 401 response.
+ *
+ * @param user_data The user data as specified in the credential.
+ * @param pool Pool to allocate memory.
+ * @param realm On return, the function should fill in with
+ * realm if application wants to use long term
+ * credential. Otherwise application should set
+ * empty string for the realm.
+ * @param nonce On return, if application wants to use long
+ * term credential, it MUST fill in the nonce
+ * with some value. Otherwise if short term
+ * credential is wanted, it MAY set this value.
+ * If short term credential is wanted and the
+ * application doesn't want to include NONCE,
+ * then it must set this to empty string.
+ *
+ * @return The callback should return PJ_SUCCESS, or
+ * otherwise response message will not be
+ * created.
+ */
+ pj_status_t (*get_auth)(void *user_data,
+ pj_pool_t *pool,
+ pj_str_t *realm,
+ pj_str_t *nonce);
+
+ /**
+ * Get the password for the specified username. This function
+ * is also used to check whether the username is valid.
+ *
+ * @param user_data The user data as specified in the credential.
+ * @param realm The realm as specified in the message.
+ * @param username The username as specified in the message.
+ * @param pool Pool to allocate memory when necessary.
+ * @param data_type On return, application should fill up this
+ * argument with the type of data (which should
+ * be zero if data is a plaintext password).
+ * @param data On return, application should fill up this
+ * argument with the password according to
+ * data_type.
+ *
+ * @return The callback should return PJ_SUCCESS if
+ * username has been successfully verified
+ * and password was obtained. If non-PJ_SUCCESS
+ * is returned, it is assumed that the
+ * username is not valid.
+ */
+ pj_status_t (*get_password)(void *user_data,
+ const pj_str_t *realm,
+ const pj_str_t *username,
+ pj_pool_t *pool,
+ int *data_type,
+ pj_str_t *data);
+
+ /**
+ * This callback will be called to verify that the NONCE given
+ * in the message can be accepted. If this callback returns
+ * PJ_FALSE, 438 (Stale Nonce) response will be created.
+ *
+ * @param user_data The user data as specified in the credential.
+ * @param realm The realm as specified in the message.
+ * @param username The username as specified in the message.
+ * @param nonce The nonce to be verified.
+ *
+ * @return The callback MUST return non-zero if the
+ * NONCE can be accepted.
+ */
+ pj_bool_t (*verify_nonce)(void *user_data,
+ const pj_str_t *realm,
+ const pj_str_t *username,
+ const pj_str_t *nonce);
+
+ } dyn_cred;
+
+ } data;
+
+} pj_stun_auth_cred;
+
+
+/**
+ * Duplicate authentication credential.
+ *
+ * @param pool Pool to be used to allocate memory.
+ * @param dst Destination credential.
+ * @param src Source credential.
+ */
+PJ_DECL(void) pj_stun_auth_cred_dup(pj_pool_t *pool,
+ pj_stun_auth_cred *dst,
+ const pj_stun_auth_cred *src);
+
+
+/**
+ * Verify credential in the STUN message. Note that before calling this
+ * function, application must have checked that the message contains
+ * PJ_STUN_ATTR_MESSAGE_INTEGRITY attribute by calling pj_stun_msg_find_attr()
+ * function, because this function will reject the message with 401 error
+ * if it doesn't contain PJ_STUN_ATTR_MESSAGE_INTEGRITY attribute.
+ *
+ * @param pkt The original packet which has been parsed into
+ * the message. This packet MUST NOT have been modified
+ * after the parsing.
+ * @param pkt_len The length of the packet.
+ * @param msg The parsed message to be verified.
+ * @param cred Pointer to credential to be used to authenticate
+ * the message.
+ * @param pool If response is to be created, then memory will
+ * be allocated from this pool.
+ * @param p_response Optional pointer to receive the response message
+ * then the credential in the request fails to
+ * authenticate.
+ *
+ * @return PJ_SUCCESS if credential is verified successfully.
+ * If the verification fails and \a p_response is not
+ * NULL, an appropriate response will be returned in
+ * \a p_response.
+ */
+PJ_DECL(pj_status_t) pj_stun_verify_credential(const pj_uint8_t *pkt,
+ unsigned pkt_len,
+ const pj_stun_msg *msg,
+ pj_stun_auth_cred *cred,
+ pj_pool_t *pool,
+ pj_stun_msg **p_response);
+
+
+
+
+/**
+ * @}
+ */
+
+
+/* Calculate HMAC-SHA1 key for long term credential, by getting
+ * MD5 digest of username, realm, and password.
+ */
+void pj_stun_calc_md5_key(pj_uint8_t digest[16],
+ const pj_str_t *realm,
+ const pj_str_t *username,
+ const pj_str_t *passwd);
+
+
+PJ_END_DECL
+
+
+#endif /* __PJ_STUN_AUTH_H__ */
+
diff --git a/pjlib-util/include/pjlib-util/stun_msg.h b/pjlib-util/include/pjlib-util/stun_msg.h
index 6d4d5a6b..de7f73d2 100644
--- a/pjlib-util/include/pjlib-util/stun_msg.h
+++ b/pjlib-util/include/pjlib-util/stun_msg.h
@@ -510,7 +510,7 @@ typedef struct pj_stun_attr_hdr
\endverbatim
*/
-typedef struct pj_stun_generic_ip_addr_attr
+typedef struct pj_stun_ip_addr_attr
{
/**
* Standard STUN attribute header.
@@ -526,7 +526,7 @@ typedef struct pj_stun_generic_ip_addr_attr
pj_sockaddr_in6 ipv6; /**< IPv6 socket address. */
} addr;
-} pj_stun_generic_ip_addr_attr;
+} pj_stun_ip_addr_attr;
/**
@@ -548,7 +548,7 @@ typedef struct pj_stun_empty_attr
* USERNAME, PASSWORD, SERVER, REALM, and NONCE attributes. Note that for REALM and
* NONCE attributes, the text MUST be quoted with.
*/
-typedef struct pj_stun_generic_string_attr
+typedef struct pj_stun_string_attr
{
/**
* Standard STUN attribute header.
@@ -560,14 +560,14 @@ typedef struct pj_stun_generic_string_attr
*/
pj_str_t value;
-} pj_stun_generic_string_attr;
+} pj_stun_string_attr;
/**
* This structure represents a generic STUN attributes with 32bit (unsigned)
* integer value, such as STUN FINGERPRINT and REFRESH-INTERVAL attributes.
*/
-typedef struct pj_stun_generic_uint_attr
+typedef struct pj_stun_uint_attr
{
/**
* Standard STUN attribute header.
@@ -579,7 +579,7 @@ typedef struct pj_stun_generic_uint_attr
*/
pj_uint32_t value;
-} pj_stun_generic_uint_attr;
+} pj_stun_uint_attr;
/**
@@ -613,7 +613,7 @@ typedef struct pj_stun_binary_attr
* STUN message type. Since it uses the SHA1 hash, the HMAC will be 20
* bytes.
*/
-typedef struct pj_stun_msg_integrity_attr
+typedef struct pj_stun_msgint_attr
{
/**
* Standard STUN attribute header.
@@ -625,7 +625,7 @@ typedef struct pj_stun_msg_integrity_attr
*/
pj_uint8_t hmac[20];
-} pj_stun_msg_integrity_attr;
+} pj_stun_msgint_attr;
/**
@@ -634,7 +634,7 @@ typedef struct pj_stun_msg_integrity_attr
* the CRC-32 of the STUN message up to (but excluding) the FINGERPRINT
* attribute itself, xor-d with the 32 bit value 0x5354554e
*/
-typedef struct pj_stun_generic_uint_attr pj_stun_fingerprint_attr;
+typedef struct pj_stun_uint_attr pj_stun_fingerprint_attr;
/**
@@ -655,7 +655,7 @@ typedef struct pj_stun_generic_uint_attr pj_stun_fingerprint_attr;
\endverbatim
*/
-typedef struct pj_stun_error_code_attr
+typedef struct pj_stun_errcode_attr
{
/**
* Standard STUN attribute header.
@@ -682,7 +682,7 @@ typedef struct pj_stun_error_code_attr
*/
pj_str_t reason;
-} pj_stun_error_code_attr;
+} pj_stun_errcode_attr;
/**
@@ -692,7 +692,7 @@ typedef struct pj_stun_error_code_attr
* 3261 [11], and will thus contain a quoted string (including the
* quotes).
*/
-typedef struct pj_stun_generic_string_attr pj_stun_realm_attr;
+typedef struct pj_stun_string_attr pj_stun_realm_attr;
/**
@@ -702,7 +702,7 @@ typedef struct pj_stun_generic_string_attr pj_stun_realm_attr;
* RFC 3261 [11]. See RFC 2617 [7] for guidance on selection of nonce
* values in a server.
*/
-typedef struct pj_stun_generic_string_attr pj_stun_nonce_attr;
+typedef struct pj_stun_string_attr pj_stun_nonce_attr;
/**
@@ -739,7 +739,7 @@ typedef struct pj_stun_unknown_attr
* This structure describes STUN MAPPED-ADDRESS attribute.
* The MAPPED-ADDRESS attribute indicates the mapped transport address.
*/
-typedef struct pj_stun_generic_ip_addr_attr pj_stun_mapped_addr_attr;
+typedef struct pj_stun_ip_addr_attr pj_stun_mapped_addr_attr;
/**
@@ -751,7 +751,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_mapped_addr_attr;
* obfuscated through the XOR function, STUN messages are able to pass
* through NATs which would otherwise interfere with STUN.
*/
-typedef struct pj_stun_generic_ip_addr_attr pj_stun_xor_mapped_addr_attr;
+typedef struct pj_stun_ip_addr_attr pj_stun_xor_mapped_addr_attr;
/**
@@ -762,7 +762,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_xor_mapped_addr_attr;
* only as a tool for diagnostic and debugging purposes. The value of
* SERVER is variable length.
*/
-typedef struct pj_stun_generic_string_attr pj_stun_server_attr;
+typedef struct pj_stun_string_attr pj_stun_server_attr;
/**
@@ -771,7 +771,7 @@ typedef struct pj_stun_generic_string_attr pj_stun_server_attr;
* different STUN server to try. It is encoded in the same way as
* MAPPED-ADDRESS.
*/
-typedef struct pj_stun_generic_ip_addr_attr pj_stun_alt_server_attr;
+typedef struct pj_stun_ip_addr_attr pj_stun_alt_server_attr;
/**
@@ -780,7 +780,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_alt_server_attr;
* server suggests the client should use between refreshes of the NAT
* bindings between the client and server.
*/
-typedef struct pj_stun_generic_uint_attr pj_stun_refresh_interval_attr;
+typedef struct pj_stun_uint_attr pj_stun_refresh_interval_attr;
/**
@@ -792,7 +792,7 @@ typedef struct pj_stun_generic_uint_attr pj_stun_refresh_interval_attr;
* Note that the usage of this attribute has been deprecated by the
* RFC 3489-bis standard.
*/
-typedef struct pj_stun_generic_ip_addr_attr pj_stun_response_addr_attr;
+typedef struct pj_stun_ip_addr_attr pj_stun_response_addr_attr;
/**
@@ -807,7 +807,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_response_addr_attr;
* Note that the usage of this attribute has been deprecated by the
* RFC 3489-bis standard.
*/
-typedef struct pj_stun_generic_ip_addr_attr pj_stun_changed_addr_attr;
+typedef struct pj_stun_ip_addr_attr pj_stun_changed_addr_attr;
/**
@@ -827,7 +827,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_changed_addr_attr;
* Note that the usage of this attribute has been deprecated by the
* RFC 3489-bis standard.
*/
-typedef struct pj_stun_generic_uint_attr pj_stun_change_request_attr;
+typedef struct pj_stun_uint_attr pj_stun_change_request_attr;
/**
* This structure describes STUN SOURCE-ADDRESS attribute.
@@ -839,7 +839,7 @@ typedef struct pj_stun_generic_uint_attr pj_stun_change_request_attr;
* Note that the usage of this attribute has been deprecated by the
* RFC 3489-bis standard.
*/
-typedef struct pj_stun_generic_ip_addr_attr pj_stun_src_addr_attr;
+typedef struct pj_stun_ip_addr_attr pj_stun_src_addr_attr;
/**
@@ -851,7 +851,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_src_addr_attr;
* traceability, so that a STUN server cannot be used as a reflector for
* denial-of-service attacks.
*/
-typedef struct pj_stun_generic_ip_addr_attr pj_stun_reflected_from_attr;
+typedef struct pj_stun_ip_addr_attr pj_stun_reflected_from_attr;
/**
@@ -861,7 +861,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_reflected_from_attr;
* the USERNAME MUST be included in any request that contains the
* MESSAGE-INTEGRITY attribute.
*/
-typedef struct pj_stun_generic_string_attr pj_stun_username_attr;
+typedef struct pj_stun_string_attr pj_stun_username_attr;
/**
@@ -869,7 +869,7 @@ typedef struct pj_stun_generic_string_attr pj_stun_username_attr;
* If the message type is Shared Secret Response it MUST include the
* PASSWORD attribute.
*/
-typedef struct pj_stun_generic_string_attr pj_stun_password_attr;
+typedef struct pj_stun_string_attr pj_stun_password_attr;
/**
@@ -879,7 +879,7 @@ typedef struct pj_stun_generic_string_attr pj_stun_password_attr;
* from or to the client. It is a 32 bit value representing the number
* of seconds remaining until expiration.
*/
-typedef struct pj_stun_generic_uint_attr pj_stun_lifetime_attr;
+typedef struct pj_stun_uint_attr pj_stun_lifetime_attr;
/**
@@ -888,7 +888,7 @@ typedef struct pj_stun_generic_uint_attr pj_stun_lifetime_attr;
* kbits per second, that the client expects to use on the binding. The
* value represents the sum in the receive and send directions.
*/
-typedef struct pj_stun_generic_uint_attr pj_stun_bandwidth_attr;
+typedef struct pj_stun_uint_attr pj_stun_bandwidth_attr;
/**
@@ -896,7 +896,7 @@ typedef struct pj_stun_generic_uint_attr pj_stun_bandwidth_attr;
* The REMOTE-ADDRESS specifies the address and port of the peer as seen
* from the STUN relay server.
*/
-typedef struct pj_stun_generic_ip_addr_attr pj_stun_remote_addr_attr;
+typedef struct pj_stun_ip_addr_attr pj_stun_remote_addr_attr;
/**
@@ -914,7 +914,7 @@ typedef struct pj_stun_binary_attr pj_stun_data_attr;
* The RELAY-ADDRESS is present in Allocate responses. It specifies the
* address and port that the server allocated to the client.
*/
-typedef struct pj_stun_generic_ip_addr_attr pj_stun_relay_addr_attr;
+typedef struct pj_stun_ip_addr_attr pj_stun_relay_addr_attr;
/**
@@ -933,7 +933,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_relay_addr_attr;
\endverbatim
*/
-typedef struct pj_stun_generic_uint_attr pj_stun_requested_addr_type;
+typedef struct pj_stun_uint_attr pj_stun_requested_addr_type;
/**
* This describes the STUN REQUESTED-PORT-PROPS attribute.
@@ -953,7 +953,7 @@ typedef struct pj_stun_generic_uint_attr pj_stun_requested_addr_type;
\endverbatim
*/
-typedef struct pj_stun_generic_uint_attr pj_stun_requested_port_props_attr;
+typedef struct pj_stun_uint_attr pj_stun_requested_port_props_attr;
/**
@@ -962,7 +962,7 @@ typedef struct pj_stun_generic_uint_attr pj_stun_requested_port_props_attr;
* protocol for the allocated transport address. It is a 32 bit
* unsigned integer. Its values are: 0x0000 for UDP and 0x0000 for TCP.
*/
-typedef struct pj_stun_generic_uint_attr pj_stun_requested_transport_attr;
+typedef struct pj_stun_uint_attr pj_stun_requested_transport_attr;
/**
@@ -970,7 +970,7 @@ typedef struct pj_stun_generic_uint_attr pj_stun_requested_transport_attr;
* The REQUESTED-IP attribute is used by the client to request that a
* specific IP address be allocated to it.
*/
-typedef struct pj_stun_generic_ip_addr_attr pj_stun_requested_ip_attr;
+typedef struct pj_stun_ip_addr_attr pj_stun_requested_ip_attr;
/**
* This describes the XOR-REFLECTED-FROM attribute, as described by
@@ -982,7 +982,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_requested_ip_attr;
* the private network address. XOR-REFLECTED-FROM has identical syntax
* to XOR-MAPPED-ADDRESS.
*/
-typedef struct pj_stun_generic_ip_addr_attr pj_stun_xor_reflected_from_attr;
+typedef struct pj_stun_ip_addr_attr pj_stun_xor_reflected_from_attr;
/**
* This describes the PRIORITY attribute from draft-ietf-mmusic-ice-13.
@@ -991,7 +991,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_xor_reflected_from_attr;
* by this check. It is a 32 bit unsigned integer, and has an attribute
* type of 0x0024.
*/
-typedef struct pj_stun_generic_uint_attr pj_stun_priority_attr;
+typedef struct pj_stun_uint_attr pj_stun_priority_attr;
/**
* This describes the USE-CANDIDATE attribute from draft-ietf-mmusic-ice-13.
@@ -1010,7 +1010,7 @@ typedef struct pj_stun_empty_attr pj_stun_use_candidate_attr;
* STUN client to 'walk backwards' and communicate directly with all of
* the STUN-aware NATs along the path.
*/
-typedef pj_stun_generic_ip_addr_attr pj_stun_xor_internal_addr_attr;
+typedef pj_stun_ip_addr_attr pj_stun_xor_internal_addr_attr;
/**
* This describes the STUN TIMER-VAL attribute.
@@ -1018,7 +1018,7 @@ typedef pj_stun_generic_ip_addr_attr pj_stun_xor_internal_addr_attr;
* Active Destination response. It conveys from the server, to the
* client, the value of the timer used in the server state machine.
*/
-typedef struct pj_stun_generic_uint_attr pj_stun_timer_val_attr;
+typedef struct pj_stun_uint_attr pj_stun_timer_val_attr;
/**
@@ -1047,7 +1047,7 @@ typedef struct pj_stun_msg
/** STUN decoding options */
-enum pj_stun_options
+enum pj_stun_decode_options
{
/**
* Tell the decoder that the message was received from datagram
@@ -1063,6 +1063,7 @@ enum pj_stun_options
PJ_STUN_CHECK_PACKET = 2
};
+
/**
* Get STUN message method name.
*
@@ -1207,15 +1208,15 @@ PJ_DECL(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
* @param pdu The packet buffer.
* @param pdu_len The length of the packet buffer.
* @param options Additional options to be applied in the checking,
- * which can be taken from pj_stun_options. One of the
- * useful option is PJ_STUN_IS_DATAGRAM which means that
- * the pdu represents a whole STUN packet.
+ * which can be taken from pj_stun_decode_options. One
+ * of the useful option is PJ_STUN_IS_DATAGRAM which
+ * means that the pdu represents a whole STUN packet.
*
* @return PJ_SUCCESS if the PDU is a potentially valid STUN
* message.
*/
-PJ_DECL(pj_status_t) pj_stun_msg_check(const pj_uint8_t *pdu, unsigned pdu_len,
- unsigned options);
+PJ_DECL(pj_status_t) pj_stun_msg_check(const pj_uint8_t *pdu,
+ unsigned pdu_len, unsigned options);
/**
@@ -1224,7 +1225,7 @@ PJ_DECL(pj_status_t) pj_stun_msg_check(const pj_uint8_t *pdu, unsigned pdu_len,
* @param pool Pool to allocate the message.
* @param pdu The incoming packet to be parsed.
* @param pdu_len The length of the incoming packet.
- * @param options Parsing flags, according to pj_stun_options.
+ * @param options Parsing flags, according to pj_stun_decode_options.
* @param p_msg Pointer to receive the parsed message.
* @param p_parsed_len Optional pointer to receive how many bytes have
* been parsed for the STUN message. This is useful
@@ -1247,138 +1248,6 @@ PJ_DECL(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
unsigned *p_parsed_len,
pj_stun_msg **p_response);
-typedef enum pj_stun_auth_policy_type
-{
- PJ_STUN_POLICY_NONE,
- PJ_STUN_POLICY_STATIC_SHORT_TERM,
- PJ_STUN_POLICY_STATIC_LONG_TERM,
- PJ_STUN_POLICY_DYNAMIC
-} pj_stun_auth_policy_type;
-
-typedef struct pj_stun_auth_policy
-{
- pj_stun_auth_policy_type type;
- void *user_data;
-
- union
- {
- struct
- {
- pj_str_t username;
- pj_str_t password;
- pj_str_t nonce;
- } static_short_term;
-
- struct
- {
- pj_str_t realm;
- pj_str_t username;
- pj_str_t password;
- pj_str_t nonce;
- } static_long_term;
-
- struct
- {
- /**
- * This callback is called by pj_stun_verify_credential() when
- * server needs to challenge the request with 401 response.
- *
- * @param user_data The user data as specified in the policy.
- * @param pool Pool to allocate memory.
- * @param realm On return, the function should fill in with
- * realm if application wants to use long term
- * credential. Otherwise application should set
- * empty string for the realm.
- * @param nonce On return, if application wants to use long
- * term credential, it MUST fill in the nonce
- * with some value. Otherwise if short term
- * credential is wanted, it MAY set this value.
- * If short term credential is wanted and the
- * application doesn't want to include NONCE,
- * then it must set this to empty string.
- *
- * @return The callback should return PJ_SUCCESS, or
- * otherwise response message will not be
- * created.
- */
- pj_status_t (*get_auth)(void *user_data,
- pj_pool_t *pool,
- pj_str_t *realm,
- pj_str_t *nonce);
-
- /**
- * Get the password for the specified username. This function
- * is also used to check whether the username is valid.
- *
- * @param user_data The user data as specified in the policy.
- * @param realm The realm as specified in the message.
- * @param username The username as specified in the message.
- * @param pool Pool to allocate memory when necessary.
- * @param password On return, application should fill up this
- * argument with the password.
- *
- * @return The callback should return PJ_SUCCESS if
- * username has been successfully verified
- * and password was obtained. If non-PJ_SUCCESS
- * is returned, it is assumed that the
- * username is not valid.
- */
- pj_status_t (*get_password)(void *user_data,
- const pj_str_t *realm,
- const pj_str_t *username,
- pj_pool_t *pool,
- pj_str_t *password);
- pj_bool_t (*require_nonce)(void *user_data,
- const pj_str_t *realm,
- const pj_str_t *username);
- pj_bool_t (*verify_nonce)(void *data,
- const pj_str_t *realm,
- const pj_str_t *username,
- const pj_str_t *nonce);
- pj_status_t (*make_nonce)(void *user_data,
- const pj_str_t *realm,
- const pj_str_t *username,
- pj_pool_t *pool,
- pj_str_t *nonce);
- } dynamic;
-
- } data;
-
-} pj_stun_auth_policy;
-
-
-/**
- * Verify credential in the STUN message. Note that before calling this
- * function, application must have checked that the message contains
- * PJ_STUN_ATTR_MESSAGE_INTEGRITY attribute by calling pj_stun_msg_find_attr()
- * function, because this function will reject the message with 401 error
- * if it doesn't contain PJ_STUN_ATTR_MESSAGE_INTEGRITY attribute.
- *
- * @param pkt The original packet which has been parsed into
- * the message. This packet MUST NOT have been modified
- * after the parsing.
- * @param pkt_len The length of the packet.
- * @param msg The parsed message to be verified.
- * @param policy Pointer to authentication policy.
- * @param pool If response is to be created, then memory will
- * be allocated from this pool.
- * @param p_response Optional pointer to receive the response message
- * then the credential in the request fails to
- * authenticate.
- *
- * @return PJ_SUCCESS if credential is verified successfully.
- * If the verification fails and \a p_response is not
- * NULL, an appropriate response will be returned in
- * \a p_response.
- */
-PJ_DECL(pj_status_t) pj_stun_verify_credential(const pj_uint8_t *pkt,
- unsigned pkt_len,
- const pj_stun_msg *msg,
- pj_stun_auth_policy *policy,
- pj_pool_t *pool,
- pj_stun_msg **p_response);
-
-
/**
* Dump STUN message to a printable string output.
*
@@ -1430,13 +1299,12 @@ PJ_DECL(pj_stun_attr_hdr*) pj_stun_msg_find_attr(const pj_stun_msg *msg,
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
-PJ_DECL(pj_status_t)
-pj_stun_generic_ip_addr_attr_create(pj_pool_t *pool,
- int attr_type,
- pj_bool_t xor_ed,
- const pj_sockaddr_t *addr,
- unsigned addr_len,
- pj_stun_generic_ip_addr_attr **p_attr);
+PJ_DECL(pj_status_t) pj_stun_ip_addr_attr_create(pj_pool_t *pool,
+ int attr_type,
+ pj_bool_t xor_ed,
+ const pj_sockaddr_t *addr,
+ unsigned addr_len,
+ pj_stun_ip_addr_attr **p_attr);
/**
@@ -1454,13 +1322,12 @@ pj_stun_generic_ip_addr_attr_create(pj_pool_t *pool,
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
-PJ_DECL(pj_status_t)
-pj_stun_msg_add_generic_ip_addr_attr(pj_pool_t *pool,
- pj_stun_msg *msg,
- int attr_type,
- pj_bool_t xor_ed,
- const pj_sockaddr_t *addr,
- unsigned addr_len);
+PJ_DECL(pj_status_t) pj_stun_msg_add_ip_addr_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int attr_type,
+ pj_bool_t xor_ed,
+ const pj_sockaddr_t *addr,
+ unsigned addr_len);
/**
* Create a STUN generic string attribute.
@@ -1472,11 +1339,10 @@ pj_stun_msg_add_generic_ip_addr_attr(pj_pool_t *pool,
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
-PJ_DECL(pj_status_t)
-pj_stun_generic_string_attr_create(pj_pool_t *pool,
- int attr_type,
- const pj_str_t *value,
- pj_stun_generic_string_attr **p_attr);
+PJ_DECL(pj_status_t) pj_stun_string_attr_create(pj_pool_t *pool,
+ int attr_type,
+ const pj_str_t *value,
+ pj_stun_string_attr **p_attr);
/**
* Create and add STUN generic string attribute to the message.
@@ -1488,11 +1354,10 @@ pj_stun_generic_string_attr_create(pj_pool_t *pool,
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
-PJ_DECL(pj_status_t)
-pj_stun_msg_add_generic_string_attr(pj_pool_t *pool,
- pj_stun_msg *msg,
- int attr_type,
- const pj_str_t *value);
+PJ_DECL(pj_status_t) pj_stun_msg_add_string_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int attr_type,
+ const pj_str_t *value);
/**
* Create a STUN generic 32bit value attribute.
@@ -1504,11 +1369,10 @@ pj_stun_msg_add_generic_string_attr(pj_pool_t *pool,
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
-PJ_DECL(pj_status_t)
-pj_stun_generic_uint_attr_create(pj_pool_t *pool,
- int attr_type,
- pj_uint32_t value,
- pj_stun_generic_uint_attr **p_attr);
+PJ_DECL(pj_status_t) pj_stun_uint_attr_create(pj_pool_t *pool,
+ int attr_type,
+ pj_uint32_t value,
+ pj_stun_uint_attr **p_attr);
/**
* Create and add STUN generic 32bit value attribute to the message.
@@ -1520,11 +1384,10 @@ pj_stun_generic_uint_attr_create(pj_pool_t *pool,
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
-PJ_DECL(pj_status_t)
-pj_stun_msg_add_generic_uint_attr(pj_pool_t *pool,
- pj_stun_msg *msg,
- int attr_type,
- pj_uint32_t value);
+PJ_DECL(pj_status_t) pj_stun_msg_add_uint_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int attr_type,
+ pj_uint32_t value);
/**
@@ -1535,9 +1398,19 @@ pj_stun_msg_add_generic_uint_attr(pj_pool_t *pool,
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
-PJ_DECL(pj_status_t)
-pj_stun_msg_integrity_attr_create(pj_pool_t *pool,
- pj_stun_msg_integrity_attr **p_attr);
+PJ_DECL(pj_status_t) pj_stun_msgint_attr_create(pj_pool_t *pool,
+ pj_stun_msgint_attr **p_attr);
+
+/**
+ * Create and add STUN MESSAGE-INTEGRITY attribute.
+ *
+ * @param pool The pool to allocate memory from.
+ * @param msg The STUN message
+ *
+ * @return PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_stun_msg_add_msgint_attr(pj_pool_t *pool,
+ pj_stun_msg *msg);
/**
* Create a STUN ERROR-CODE attribute.
@@ -1550,12 +1423,27 @@ pj_stun_msg_integrity_attr_create(pj_pool_t *pool,
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
-PJ_DECL(pj_status_t)
-pj_stun_error_code_attr_create(pj_pool_t *pool,
- int err_code,
- const pj_str_t *err_reason,
- pj_stun_error_code_attr **p_attr);
+PJ_DECL(pj_status_t) pj_stun_errcode_attr_create(pj_pool_t *pool,
+ int err_code,
+ const pj_str_t *err_reason,
+ pj_stun_errcode_attr **p_attr);
+
+/**
+ * Create and add STUN ERROR-CODE attribute to the message.
+ *
+ * @param pool The pool to allocate memory from.
+ * @param msg The STUN mesage.
+ * @param err_code STUN error code.
+ * @param err_reason Optional STUN error reason. If NULL is given, the
+ * standard error reason will be given.
+ *
+ * @return PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_stun_msg_add_errcode_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int err_code,
+ const pj_str_t *err_reason);
/**
* Create instance of STUN UNKNOWN-ATTRIBUTES attribute and copy the
@@ -1568,11 +1456,10 @@ pj_stun_error_code_attr_create(pj_pool_t *pool,
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
-PJ_DECL(pj_status_t)
-pj_stun_unknown_attr_create(pj_pool_t *pool,
- unsigned attr_cnt,
- const pj_uint16_t attr[],
- pj_stun_unknown_attr **p_attr);
+PJ_DECL(pj_status_t) pj_stun_unknown_attr_create(pj_pool_t *pool,
+ unsigned attr_cnt,
+ const pj_uint16_t attr[],
+ pj_stun_unknown_attr **p_attr);
/**
* Create and add STUN UNKNOWN-ATTRIBUTES attribute to the message.
@@ -1584,11 +1471,10 @@ pj_stun_unknown_attr_create(pj_pool_t *pool,
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
-PJ_DECL(pj_status_t)
-pj_stun_msg_add_unknown_attr(pj_pool_t *pool,
- pj_stun_msg *msg,
- unsigned attr_cnt,
- const pj_uint16_t attr[]);
+PJ_DECL(pj_status_t) pj_stun_msg_add_unknown_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ unsigned attr_cnt,
+ const pj_uint16_t attr[]);
/**
* Create STUN binary attribute.
@@ -1603,12 +1489,11 @@ pj_stun_msg_add_unknown_attr(pj_pool_t *pool,
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
-PJ_DECL(pj_status_t)
-pj_stun_binary_attr_create(pj_pool_t *pool,
- int attr_type,
- const pj_uint8_t *data,
- unsigned length,
- pj_stun_binary_attr **p_attr);
+PJ_DECL(pj_status_t) pj_stun_binary_attr_create(pj_pool_t *pool,
+ int attr_type,
+ const pj_uint8_t *data,
+ unsigned length,
+ pj_stun_binary_attr **p_attr);
/**
* Create STUN binary attribute and add the attribute to the message.
@@ -1624,12 +1509,11 @@ pj_stun_binary_attr_create(pj_pool_t *pool,
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
-PJ_DECL(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_DECL(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);
/**
diff --git a/pjlib-util/include/pjlib-util/stun_server.h b/pjlib-util/include/pjlib-util/stun_server.h
deleted file mode 100644
index 15ecf308..00000000
--- a/pjlib-util/include/pjlib-util/stun_server.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/* $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 __PJ_STUN_SERVER_H__
-#define __PJ_STUN_SERVER_H__
-
-/**
- * @file stun_server.h
- * @brief STUN server side services.
- */
-
-#include <pjlib-util/stun_msg.h>
-#include <pjlib-util/stun_endpoint.h>
-
-
-PJ_BEGIN_DECL
-
-
-/* **************************************************************************/
-/**
- * @defgroup PJLIB_UTIL_STUN_SERVER STUN Server Side Services
- * @brief STUN server side services
- * @ingroup PJLIB_UTIL_STUN
- * @{
- */
-
-typedef struct pj_stun_service pj_stun_service;
-
-
-/**
- * STUN service handler.
- */
-typedef struct pj_stun_service_handler
-{
- /**
- * The STUN message type.
- */
- int msg_type;
-
- /**
- * Callback to be called to handle this STUN message type.
- *
- * @param svc The service.
- * @param msg The STUN message.
- */
- pj_status_t (*handle_msg)(pj_stun_service *svc,
- void *handle_data,
- const pj_stun_msg *msg);
-
-} pj_stun_service_handler;
-
-
-/**
- * Create STUN service.
- */
-PJ_DECL(pj_status_t) pj_stun_service_create(pj_pool_t *pool,
- const char *name,
- unsigned options,
- unsigned handler_cnt,
- pj_stun_service_handler cb[],
- void *user_data,
- pj_stun_service **p_svc);
-
-/**
- * Destroy STUN service
- */
-PJ_DECL(pj_status_t) pj_stun_service_destroy(pj_stun_service *svc);
-
-
-/**
- * Get user data associated with the STUN service.
- */
-PJ_DECL(void*) pj_stun_service_get_user_data(pj_stun_service *svc);
-
-
-/**
- * Instruct the STUN service to handle incoming STUN message.
- */
-PJ_DECL(pj_status_t) pj_stun_service_handle_msg(pj_stun_service *svc,
- void *handle_data,
- const pj_stun_msg *msg);
-
-
-
-/**
- * @}
- */
-
-
-PJ_END_DECL
-
-
-#endif /* __PJ_STUN_SERVER_H__ */
-
diff --git a/pjlib-util/include/pjlib-util/stun_session.h b/pjlib-util/include/pjlib-util/stun_session.h
index 610302fa..8fe7b1ca 100644
--- a/pjlib-util/include/pjlib-util/stun_session.h
+++ b/pjlib-util/include/pjlib-util/stun_session.h
@@ -20,6 +20,7 @@
#define __PJLIB_UTIL_STUN_SESSION_H__
#include <pjlib-util/stun_msg.h>
+#include <pjlib-util/stun_auth.h>
#include <pjlib-util/stun_endpoint.h>
#include <pjlib-util/stun_transaction.h>
#include <pj/list.h>
@@ -147,7 +148,6 @@ struct pj_stun_tx_data
unsigned max_len; /**< Length of packet buffer. */
unsigned pkt_size; /**< The actual length of STUN pkt. */
- unsigned options; /**< Options specified when sending */
unsigned addr_len; /**< Length of destination address. */
const pj_sockaddr_t *dst_addr; /**< Destination address. */
@@ -156,52 +156,21 @@ struct pj_stun_tx_data
/**
- * Options that can be specified when creating or sending outgoing STUN
- * messages. These options may be specified as bitmask.
- */
-enum pj_stun_session_send_option
-{
- /**
- * Add short term credential to the message. This option may not be used
- * together with PJ_STUN_USE_LONG_TERM_CRED option.
- */
- PJ_STUN_USE_SHORT_TERM_CRED = 1,
-
- /**
- * Add long term credential to the message. This option may not be used
- * together with PJ_STUN_USE_SHORT_TERM_CRED option.
- */
- PJ_STUN_USE_LONG_TERM_CRED = 2,
-
- /**
- * Add STUN fingerprint to the message.
- */
- PJ_STUN_USE_FINGERPRINT = 4,
-
- /**
- * Instruct the session to cache outgoing response. This can only be
- * used when sending outgoing response message, and when it's specified,
- * the session will use \a res_cache_msec settings in pj_stun_endpoint
- * as the duration of the cache.
- */
- PJ_STUN_CACHE_RESPONSE = 8
-};
-
-
-/**
* Create a STUN session.
*
- * @param endpt The STUN endpoint, to be used to register timers etc.
- * @param name Optional name to be associated with this instance. The
- * name will be used for example for logging purpose.
- * @param cb Session callback.
- * @param p_sess Pointer to receive STUN session instance.
+ * @param endpt The STUN endpoint, to be used to register timers etc.
+ * @param name Optional name to be associated with this instance. The
+ * name will be used for example for logging purpose.
+ * @param cb Session callback.
+ * @param fingerprint Enable message fingerprint for outgoing messages.
+ * @param p_sess Pointer to receive STUN session instance.
*
* @return PJ_SUCCESS on success, or the appropriate error code.
*/
PJ_DECL(pj_status_t) pj_stun_session_create(pj_stun_endpoint *endpt,
const char *name,
const pj_stun_session_cb *cb,
+ pj_bool_t fingerprint,
pj_stun_session **p_sess);
/**
@@ -235,42 +204,32 @@ PJ_DECL(pj_status_t) pj_stun_session_set_user_data(pj_stun_session *sess,
PJ_DECL(void*) pj_stun_session_get_user_data(pj_stun_session *sess);
/**
- * Save a long term credential to be used by this STUN session when sending
- * outgoing messages. After long term credential is configured, application
- * may specify PJ_STUN_USE_LONG_TERM_CRED option when sending outgoing STUN
- * message to send the long term credential in the message.
+ * Set server name to be included in all response.
*
* @param sess The STUN session instance.
- * @param realm Realm of the long term credential.
- * @param user The user name.
- * @param passwd The pain-text password.
+ * @param srv_name Server name string.
*
- * @return PJ_SUCCESS on success, or the appropriate error code.
+ * @return The user data associated with this STUN session.
*/
-PJ_DECL(pj_status_t)
-pj_stun_session_set_long_term_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_set_server_name(pj_stun_session *sess,
+ const pj_str_t *srv_name);
/**
- * Save a short term credential to be used by this STUN session when sending
- * outgoing messages. After short term credential is configured, application
- * may specify PJ_STUN_USE_SHORT_TERM_CRED option when sending outgoing STUN
- * message to send the short term credential in the message.
+ * Set credential to be used by this session. Once credential is set, all
+ * outgoing messages will include MESSAGE-INTEGRITY, and all incoming
+ * message will be authenticated against this credential.
+ *
+ * To disable authentication after it has been set, call this function
+ * again with NULL as the argument.
*
* @param sess The STUN session instance.
- * @param user The user name.
- * @param passwd The pain-text password.
+ * @param cred The credential to be used by this session. If NULL
+ * is specified, authentication will be disabled.
*
* @return PJ_SUCCESS on success, or the appropriate error code.
*/
-PJ_DECL(pj_status_t)
-pj_stun_session_set_short_term_credential(pj_stun_session *sess,
- const pj_str_t *user,
- const pj_str_t *passwd);
-
+PJ_DECL(void) pj_stun_session_set_credential(pj_stun_session *sess,
+ const pj_stun_auth_cred *cred);
/**
* Create a STUN Bind request message. After the message has been
@@ -409,7 +368,7 @@ PJ_DECL(pj_status_t) pj_stun_session_create_response(pj_stun_session *sess,
* to actually send the message to the wire.
*
* @param sess The STUN session instance.
- * @param options Optional flags, from pj_stun_session_send_option.
+ * @param cache_res If PJ_TRUE then response will be cached.
* @param dst_addr The destination socket address.
* @param addr_len Length of destination address.
* @param tdata The STUN transmit data containing the STUN message to
@@ -418,7 +377,7 @@ PJ_DECL(pj_status_t) pj_stun_session_create_response(pj_stun_session *sess,
* @return PJ_SUCCESS on success, or the appropriate error code.
*/
PJ_DECL(pj_status_t) pj_stun_session_send_msg(pj_stun_session *sess,
- unsigned options,
+ pj_bool_t cache_res,
const pj_sockaddr_t *dst_addr,
unsigned addr_len,
pj_stun_tx_data *tdata);
diff --git a/pjlib-util/src/pjlib-util/errno.c b/pjlib-util/src/pjlib-util/errno.c
index 11e67c68..a60b3184 100644
--- a/pjlib-util/src/pjlib-util/errno.c
+++ b/pjlib-util/src/pjlib-util/errno.c
@@ -68,6 +68,23 @@ static const struct
PJ_BUILD_ERR( PJLIB_UTIL_EDNS_NXRRSET, "DNS \"The RRset (name, type) does not exist\""),
PJ_BUILD_ERR( PJLIB_UTIL_EDNS_NOTAUTH, "DNS \"Not authorized\""),
PJ_BUILD_ERR( PJLIB_UTIL_EDNS_NOTZONE, "DNS \"The zone specified is not a zone\""),
+
+ /* STUN */
+ PJ_BUILD_ERR( PJLIB_UTIL_ESTUNTOOMANYATTR, "Too many STUN attributes"),
+ PJ_BUILD_ERR( PJLIB_UTIL_ESTUNUNKNOWNATTR, "Unknown STUN attribute"),
+ PJ_BUILD_ERR( PJLIB_UTIL_ESTUNINADDRLEN, "Invalid STUN socket address length"),
+ PJ_BUILD_ERR( PJLIB_UTIL_ESTUNIPV6NOTSUPP, "STUN IPv6 attribute not supported"),
+ PJ_BUILD_ERR( PJLIB_UTIL_ESTUNNOTRESPONSE, "Expecting STUN response message"),
+ PJ_BUILD_ERR( PJLIB_UTIL_ESTUNINVALIDID, "STUN transaction ID mismatch"),
+ PJ_BUILD_ERR( PJLIB_UTIL_ESTUNNOHANDLER, "Unable to find STUN handler for the request"),
+ PJ_BUILD_ERR( PJLIB_UTIL_ESTUNMSGINTPOS, "Found non-FINGERPRINT attr. after MESSAGE-INTEGRITY"),
+ PJ_BUILD_ERR( PJLIB_UTIL_ESTUNFINGERPOS, "Found STUN attribute after FINGERPRINT"),
+ PJ_BUILD_ERR( PJLIB_UTIL_ESTUNNOUSERNAME, "Missing STUN USERNAME attribute"),
+ PJ_BUILD_ERR( PJLIB_UTIL_ESTUNMSGINT, "Missing/invalid STUN MESSAGE-INTEGRITY attribute"),
+ PJ_BUILD_ERR( PJLIB_UTIL_ESTUNDUPATTR, "Found duplicate STUN attribute"),
+ PJ_BUILD_ERR( PJLIB_UTIL_ESTUNNOREALM, "Missing STUN REALM attribute"),
+ PJ_BUILD_ERR( PJLIB_UTIL_ESTUNNONCE, "Missing/stale STUN NONCE attribute value"),
+ PJ_BUILD_ERR( PJLIB_UTIL_ESTUNTSXFAILED, "STUN transaction terminates with failure"),
};
#endif /* PJ_HAS_ERROR_STRING */
diff --git a/pjlib-util/src/pjlib-util/stun_auth.c b/pjlib-util/src/pjlib-util/stun_auth.c
new file mode 100644
index 00000000..abf61b6e
--- /dev/null
+++ b/pjlib-util/src/pjlib-util/stun_auth.c
@@ -0,0 +1,341 @@
+/* $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_auth.h>
+#include <pjlib-util/errno.h>
+#include <pjlib-util/hmac_sha1.h>
+#include <pjlib-util/sha1.h>
+#include <pj/assert.h>
+#include <pj/string.h>
+
+
+/* Duplicate credential */
+PJ_DEF(void) pj_stun_auth_cred_dup( pj_pool_t *pool,
+ pj_stun_auth_cred *dst,
+ const pj_stun_auth_cred *src)
+{
+ dst->type = src->type;
+
+ switch (src->type) {
+ case PJ_STUN_AUTH_CRED_STATIC:
+ pj_strdup(pool, &dst->data.static_cred.realm,
+ &src->data.static_cred.realm);
+ pj_strdup(pool, &dst->data.static_cred.username,
+ &src->data.static_cred.username);
+ dst->data.static_cred.data_type = src->data.static_cred.data_type;
+ pj_strdup(pool, &dst->data.static_cred.data,
+ &src->data.static_cred.data);
+ pj_strdup(pool, &dst->data.static_cred.nonce,
+ &src->data.static_cred.nonce);
+ break;
+ case PJ_STUN_AUTH_CRED_DYNAMIC:
+ pj_memcpy(&dst->data.dyn_cred, &src->data.dyn_cred,
+ sizeof(src->data.dyn_cred));
+ break;
+ }
+}
+
+
+PJ_INLINE(pj_uint16_t) GET_VAL16(const pj_uint8_t *pdu, unsigned pos)
+{
+ return (pj_uint16_t) ((pdu[pos] << 8) + pdu[pos+1]);
+}
+
+
+/* Send 401 response */
+static pj_status_t create_challenge(pj_pool_t *pool,
+ const pj_stun_msg *msg,
+ int err_code,
+ const pj_str_t *err_msg,
+ const pj_str_t *realm,
+ const pj_str_t *nonce,
+ pj_stun_msg **p_response)
+{
+ pj_stun_msg *response;
+ pj_str_t tmp_nonce;
+ pj_status_t rc;
+
+ rc = pj_stun_msg_create_response(pool, msg,
+ err_code, err_msg, &response);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+
+ if (realm && realm->slen) {
+ rc = pj_stun_msg_add_string_attr(pool, response,
+ PJ_STUN_ATTR_REALM,
+ realm);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ /* long term must include nonce */
+ if (!nonce || nonce->slen == 0) {
+ tmp_nonce = pj_str("pjstun");
+ nonce = &tmp_nonce;
+ }
+ }
+
+ if (nonce && nonce->slen) {
+ rc = pj_stun_msg_add_string_attr(pool, response,
+ PJ_STUN_ATTR_NONCE,
+ nonce);
+ if (rc != PJ_SUCCESS)
+ return rc;
+ }
+
+ *p_response = response;
+
+ return PJ_SUCCESS;
+}
+
+
+/* Verify credential */
+PJ_DEF(pj_status_t) pj_stun_verify_credential( const pj_uint8_t *pkt,
+ unsigned pkt_len,
+ const pj_stun_msg *msg,
+ pj_stun_auth_cred *cred,
+ pj_pool_t *pool,
+ pj_stun_msg **p_response)
+{
+ pj_str_t realm, nonce, password;
+ const pj_stun_msgint_attr *amsgi;
+ unsigned amsgi_pos;
+ const pj_stun_username_attr *auser;
+ pj_bool_t username_ok;
+ const pj_stun_realm_attr *arealm;
+ const pj_stun_realm_attr *anonce;
+ pj_uint8_t digest[PJ_SHA1_DIGEST_SIZE];
+ pj_uint8_t md5_digest[16];
+ pj_str_t key;
+ pj_status_t status;
+
+ /* msg and credential MUST be specified */
+ PJ_ASSERT_RETURN(pkt && pkt_len && msg && cred, PJ_EINVAL);
+
+ /* If p_response is specified, pool MUST be specified. */
+ PJ_ASSERT_RETURN(!p_response || pool, PJ_EINVAL);
+
+ if (p_response)
+ *p_response = NULL;
+
+ if (!PJ_STUN_IS_REQUEST(msg->hdr.type))
+ p_response = NULL;
+
+ /* Get realm and nonce */
+ realm.slen = nonce.slen = 0;
+ if (cred->type == PJ_STUN_AUTH_CRED_STATIC) {
+ realm = cred->data.static_cred.realm;
+ nonce = cred->data.static_cred.nonce;
+ } else if (cred->type == PJ_STUN_AUTH_CRED_DYNAMIC) {
+ status = cred->data.dyn_cred.get_auth(cred->data.dyn_cred.user_data,
+ pool, &realm, &nonce);
+ if (status != PJ_SUCCESS)
+ return status;
+ } else {
+ pj_assert(!"Unexpected");
+ return PJ_EBUG;
+ }
+
+ /* First check that MESSAGE-INTEGRITY is present */
+ amsgi = (const pj_stun_msgint_attr*)
+ pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_MESSAGE_INTEGRITY, 0);
+ if (amsgi == NULL) {
+ if (p_response) {
+ create_challenge(pool, msg, PJ_STUN_STATUS_UNAUTHORIZED, NULL,
+ &realm, &nonce, p_response);
+ }
+ return PJLIB_UTIL_ESTUNMSGINT;
+ }
+
+ /* Next check that USERNAME is present */
+ auser = (const pj_stun_username_attr*)
+ pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0);
+ if (auser == NULL) {
+ if (p_response) {
+ create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_USERNAME, NULL,
+ &realm, &nonce, p_response);
+ }
+ return PJLIB_UTIL_ESTUNNOUSERNAME;
+ }
+
+ /* Get REALM, if any */
+ arealm = (const pj_stun_realm_attr*)
+ pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REALM, 0);
+
+ /* Check if username match */
+ if (cred->type == PJ_STUN_AUTH_CRED_STATIC) {
+ username_ok = !pj_strcmp(&auser->value,
+ &cred->data.static_cred.username);
+ password = cred->data.static_cred.data;
+ } else if (cred->type == PJ_STUN_AUTH_CRED_DYNAMIC) {
+ int data_type = 0;
+ pj_status_t rc;
+ rc = cred->data.dyn_cred.get_password(cred->data.dyn_cred.user_data,
+ (arealm?&arealm->value:NULL),
+ &auser->value, pool,
+ &data_type, &password);
+ username_ok = (rc == PJ_SUCCESS);
+ } else {
+ username_ok = PJ_TRUE;
+ password.slen = 0;
+ }
+
+ if (!username_ok) {
+ /* Username mismatch */
+ if (p_response) {
+ create_challenge(pool, msg, PJ_STUN_STATUS_UNKNOWN_USERNAME, NULL,
+ &realm, &nonce, p_response);
+ }
+ return PJLIB_UTIL_ESTUNUSERNAME;
+ }
+
+
+ /* Get NONCE attribute */
+ anonce = (pj_stun_nonce_attr*)
+ pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_NONCE, 0);
+
+ /* Check for long term/short term requirements. */
+ if (realm.slen != 0 && arealm == NULL) {
+ /* Long term credential is required and REALM is not present */
+ if (p_response) {
+ create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_REALM, NULL,
+ &realm, &nonce, p_response);
+ }
+ return PJLIB_UTIL_ESTUNNOREALM;
+
+ } else if (realm.slen != 0 && arealm != NULL) {
+ /* We want long term, and REALM is present */
+
+ /* NONCE must be present. */
+ if (anonce == NULL) {
+ if (p_response) {
+ create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_NONCE,
+ NULL, &realm, &nonce, p_response);
+ }
+ return PJLIB_UTIL_ESTUNNONCE;
+ }
+
+ /* Verify REALM matches */
+ if (pj_stricmp(&arealm->value, &realm)) {
+ /* REALM doesn't match */
+ if (p_response) {
+ create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_REALM,
+ NULL, &realm, &nonce, p_response);
+ }
+ return PJLIB_UTIL_ESTUNNOREALM;
+ }
+
+ /* Valid case, will validate the message integrity later */
+
+ } else if (realm.slen == 0 && arealm != NULL) {
+ /* We want to use short term credential, but client uses long
+ * term credential. The draft doesn't mention anything about
+ * switching between long term and short term.
+ */
+
+ /* For now just accept the credential, anyway it will probably
+ * cause wrong message integrity value later.
+ */
+ } else if (realm.slen==0 && arealm == NULL) {
+ /* Short term authentication is wanted, and one is supplied */
+
+ /* Application MAY request NONCE to be supplied */
+ if (nonce.slen != 0) {
+ if (p_response) {
+ create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_NONCE,
+ NULL, &realm, &nonce, p_response);
+ }
+ return PJLIB_UTIL_ESTUNNONCE;
+ }
+ }
+
+ /* If NONCE is present, validate it */
+ if (anonce) {
+ pj_bool_t ok;
+
+ if (cred->type == PJ_STUN_AUTH_CRED_DYNAMIC) {
+ ok=cred->data.dyn_cred.verify_nonce(cred->data.dyn_cred.user_data,
+ (arealm?&arealm->value:NULL),
+ &auser->value,
+ &anonce->value);
+ } else {
+ if (nonce.slen) {
+ ok = !pj_strcmp(&anonce->value, &nonce);
+ } else {
+ ok = PJ_TRUE;
+ }
+ }
+
+ if (!ok) {
+ if (p_response) {
+ create_challenge(pool, msg, PJ_STUN_STATUS_STALE_NONCE,
+ NULL, &realm, &nonce, p_response);
+ }
+ return PJLIB_UTIL_ESTUNNONCE;
+ }
+ }
+
+ /* Get the position of MESSAGE-INTEGRITY in the packet */
+ amsgi_pos = 20+msg->hdr.length-24;
+ if (GET_VAL16(pkt, amsgi_pos) == PJ_STUN_ATTR_MESSAGE_INTEGRITY) {
+ /* Found MESSAGE-INTEGRITY as the last attribute */
+ } else {
+ amsgi_pos = 0;
+ }
+
+ if (amsgi_pos==0) {
+ amsgi_pos = 20+msg->hdr.length-8-24;
+ if (GET_VAL16(pkt, amsgi_pos) == PJ_STUN_ATTR_MESSAGE_INTEGRITY) {
+ /* Found MESSAGE-INTEGRITY before FINGERPRINT */
+ } else {
+ amsgi_pos = 0;
+ }
+ }
+
+ if (amsgi_pos==0) {
+ pj_assert(!"Unable to find MESSAGE-INTEGRITY in the message!");
+ return PJ_EBUG;
+ }
+
+ /* Determine which key to use */
+ if (realm.slen) {
+ pj_stun_calc_md5_key(md5_digest, &realm, &auser->value, &password);
+ key.ptr = (char*)md5_digest;
+ key.slen = 16;
+ } else {
+ key = password;
+ }
+
+ /* Now calculate HMAC of the message */
+ pj_hmac_sha1(pkt, amsgi_pos, (pj_uint8_t*)key.ptr, key.slen, digest);
+
+ /* Compare HMACs */
+ if (pj_memcmp(amsgi->hmac, digest, 20)) {
+ /* HMAC value mismatch */
+ if (p_response) {
+ create_challenge(pool, msg, PJ_STUN_STATUS_INTEGRITY_CHECK_FAILURE,
+ NULL, &realm, &nonce, p_response);
+ }
+ return PJLIB_UTIL_ESTUNMSGINT;
+ }
+
+ /* Everything looks okay! */
+ return PJ_SUCCESS;
+}
+
+
diff --git a/pjlib-util/src/pjlib-util/stun_msg.c b/pjlib-util/src/pjlib-util/stun_msg.c
index 6954434a..7c623ad4 100644
--- a/pjlib-util/src/pjlib-util/stun_msg.c
+++ b/pjlib-util/src/pjlib-util/stun_msg.c
@@ -21,7 +21,6 @@
#include <pjlib-util/errno.h>
#include <pjlib-util/hmac_sha1.h>
#include <pjlib-util/md5.h>
-#include <pjlib-util/sha1.h>
#include <pj/assert.h>
#include <pj/log.h>
#include <pj/os.h>
@@ -88,37 +87,37 @@ struct attr_desc
};
-static pj_status_t decode_generic_ip_addr_attr(pj_pool_t *pool,
- const pj_uint8_t *buf,
- void **p_attr);
-static pj_status_t encode_generic_ip_addr_attr(const void *a, pj_uint8_t *buf,
- unsigned len,
- unsigned *printed);
-static pj_status_t decode_generic_string_attr(pj_pool_t *pool,
- const pj_uint8_t *buf,
- void **p_attr);
-static pj_status_t encode_generic_string_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed);
-static pj_status_t decode_msg_integrity_attr(pj_pool_t *pool,
- const pj_uint8_t *buf,
- void **p_attr);
-static pj_status_t encode_msg_integrity_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed);
-static pj_status_t decode_error_code_attr(pj_pool_t *pool,
- const pj_uint8_t *buf,
- void **p_attr);
-static pj_status_t encode_error_code_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed);
+static pj_status_t decode_ip_addr_attr(pj_pool_t *pool,
+ const pj_uint8_t *buf,
+ void **p_attr);
+static pj_status_t encode_ip_addr_attr(const void *a, pj_uint8_t *buf,
+ unsigned len,
+ unsigned *printed);
+static pj_status_t decode_string_attr(pj_pool_t *pool,
+ const pj_uint8_t *buf,
+ void **p_attr);
+static pj_status_t encode_string_attr(const void *a, pj_uint8_t *buf,
+ unsigned len, unsigned *printed);
+static pj_status_t decode_msgint_attr(pj_pool_t *pool,
+ const pj_uint8_t *buf,
+ void **p_attr);
+static pj_status_t encode_msgint_attr(const void *a, pj_uint8_t *buf,
+ unsigned len, unsigned *printed);
+static pj_status_t decode_errcode_attr(pj_pool_t *pool,
+ const pj_uint8_t *buf,
+ void **p_attr);
+static pj_status_t encode_errcode_attr(const void *a, pj_uint8_t *buf,
+ unsigned len, unsigned *printed);
static pj_status_t decode_unknown_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
void **p_attr);
static pj_status_t encode_unknown_attr(const void *a, pj_uint8_t *buf,
unsigned len, unsigned *printed);
-static pj_status_t decode_generic_uint_attr(pj_pool_t *pool,
- const pj_uint8_t *buf,
- void **p_attr);
-static pj_status_t encode_generic_uint_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed);
+static pj_status_t decode_uint_attr(pj_pool_t *pool,
+ const pj_uint8_t *buf,
+ void **p_attr);
+static pj_status_t encode_uint_attr(const void *a, pj_uint8_t *buf,
+ unsigned len, unsigned *printed);
static pj_status_t decode_binary_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
void **p_attr);
@@ -142,56 +141,56 @@ struct attr_desc mandatory_attr_desc[] =
{
/* PJ_STUN_ATTR_MAPPED_ADDR, */
"MAPPED-ADDRESS",
- &decode_generic_ip_addr_attr,
- &encode_generic_ip_addr_attr
+ &decode_ip_addr_attr,
+ &encode_ip_addr_attr
},
{
/* PJ_STUN_ATTR_RESPONSE_ADDR, */
"RESPONSE-ADDRESS",
- &decode_generic_ip_addr_attr,
- &encode_generic_ip_addr_attr
+ &decode_ip_addr_attr,
+ &encode_ip_addr_attr
},
{
/* PJ_STUN_ATTR_CHANGE_REQUEST, */
"CHANGE-REQUEST",
- &decode_generic_uint_attr,
- &encode_generic_uint_attr
+ &decode_uint_attr,
+ &encode_uint_attr
},
{
/* PJ_STUN_ATTR_SOURCE_ADDR, */
"SOURCE-ADDRESS",
- &decode_generic_ip_addr_attr,
- &encode_generic_ip_addr_attr
+ &decode_ip_addr_attr,
+ &encode_ip_addr_attr
},
{
/* PJ_STUN_ATTR_CHANGED_ADDR, */
"CHANGED-ADDRESS",
- &decode_generic_ip_addr_attr,
- &encode_generic_ip_addr_attr
+ &decode_ip_addr_attr,
+ &encode_ip_addr_attr
},
{
/* PJ_STUN_ATTR_USERNAME, */
"USERNAME",
- &decode_generic_string_attr,
- &encode_generic_string_attr
+ &decode_string_attr,
+ &encode_string_attr
},
{
/* PJ_STUN_ATTR_PASSWORD, */
"PASSWORD",
- &decode_generic_string_attr,
- &encode_generic_string_attr
+ &decode_string_attr,
+ &encode_string_attr
},
{
/* PJ_STUN_ATTR_MESSAGE_INTEGRITY, */
"MESSAGE-INTEGRITY",
- &decode_msg_integrity_attr,
- &encode_msg_integrity_attr
+ &decode_msgint_attr,
+ &encode_msgint_attr
},
{
/* PJ_STUN_ATTR_ERROR_CODE, */
"ERROR-CODE",
- &decode_error_code_attr,
- &encode_error_code_attr
+ &decode_errcode_attr,
+ &encode_errcode_attr
},
{
/* PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES, */
@@ -202,8 +201,8 @@ struct attr_desc mandatory_attr_desc[] =
{
/* PJ_STUN_ATTR_REFLECTED_FROM, */
"REFLECTED-FROM",
- &decode_generic_ip_addr_attr,
- &encode_generic_ip_addr_attr
+ &decode_ip_addr_attr,
+ &encode_ip_addr_attr
},
{
/* ID 0x000C is not assigned */
@@ -214,8 +213,8 @@ struct attr_desc mandatory_attr_desc[] =
{
/* PJ_STUN_ATTR_LIFETIME, */
"LIFETIME",
- &decode_generic_uint_attr,
- &encode_generic_uint_attr
+ &decode_uint_attr,
+ &encode_uint_attr
},
{
/* ID 0x000E is not assigned */
@@ -232,8 +231,8 @@ struct attr_desc mandatory_attr_desc[] =
{
/* PJ_STUN_ATTR_BANDWIDTH, */
"BANDWIDTH",
- &decode_generic_uint_attr,
- &encode_generic_uint_attr
+ &decode_uint_attr,
+ &encode_uint_attr
},
{
/* ID 0x0011 is not assigned */
@@ -244,8 +243,8 @@ struct attr_desc mandatory_attr_desc[] =
{
/* PJ_STUN_ATTR_REMOTE_ADDRESS, */
"REMOTE-ADDRESS",
- &decode_generic_ip_addr_attr,
- &encode_generic_ip_addr_attr
+ &decode_ip_addr_attr,
+ &encode_ip_addr_attr
},
{
/* PJ_STUN_ATTR_DATA, */
@@ -256,38 +255,38 @@ struct attr_desc mandatory_attr_desc[] =
{
/* PJ_STUN_ATTR_REALM, */
"REALM",
- &decode_generic_string_attr,
- &encode_generic_string_attr
+ &decode_string_attr,
+ &encode_string_attr
},
{
/* PJ_STUN_ATTR_NONCE, */
"NONCE",
- &decode_generic_string_attr,
- &encode_generic_string_attr
+ &decode_string_attr,
+ &encode_string_attr
},
{
/* PJ_STUN_ATTR_RELAY_ADDRESS, */
"RELAY-ADDRESS",
- &decode_generic_ip_addr_attr,
- &encode_generic_ip_addr_attr
+ &decode_ip_addr_attr,
+ &encode_ip_addr_attr
},
{
/* PJ_STUN_ATTR_REQUESTED_ADDR_TYPE, */
"REQUESTED-ADDRESS-TYPE",
- &decode_generic_uint_attr,
- &encode_generic_uint_attr
+ &decode_uint_attr,
+ &encode_uint_attr
},
{
/* PJ_STUN_ATTR_REQUESTED_PORT_PROPS, */
"REQUESTED-PORT-PROPS",
- &decode_generic_uint_attr,
- &encode_generic_uint_attr
+ &decode_uint_attr,
+ &encode_uint_attr
},
{
/* PJ_STUN_ATTR_REQUESTED_TRANSPORT, */
"REQUESTED-TRANSPORT",
- &decode_generic_uint_attr,
- &encode_generic_uint_attr
+ &decode_uint_attr,
+ &encode_uint_attr
},
{
/* ID 0x001A is not assigned */
@@ -328,32 +327,32 @@ struct attr_desc mandatory_attr_desc[] =
{
/* PJ_STUN_ATTR_XOR_MAPPED_ADDRESS, */
"XOR-MAPPED-ADDRESS",
- &decode_generic_ip_addr_attr,
- &encode_generic_ip_addr_attr
+ &decode_ip_addr_attr,
+ &encode_ip_addr_attr
},
{
/* PJ_STUN_ATTR_TIMER_VAL, */
"TIMER-VAL",
- &decode_generic_uint_attr,
- &encode_generic_uint_attr
+ &decode_uint_attr,
+ &encode_uint_attr
},
{
/* PJ_STUN_ATTR_REQUESTED_IP, */
"REQUESTED-IP",
- &decode_generic_ip_addr_attr,
- &encode_generic_ip_addr_attr
+ &decode_ip_addr_attr,
+ &encode_ip_addr_attr
},
{
/* PJ_STUN_ATTR_XOR_REFLECTED_FROM, */
"XOR-REFLECTED-FROM",
- &decode_generic_ip_addr_attr,
- &encode_generic_ip_addr_attr
+ &decode_ip_addr_attr,
+ &encode_ip_addr_attr
},
{
/* PJ_STUN_ATTR_PRIORITY, */
"PRIORITY",
- &decode_generic_uint_attr,
- &encode_generic_uint_attr
+ &decode_uint_attr,
+ &encode_uint_attr
},
{
/* PJ_STUN_ATTR_USE_CANDIDATE, */
@@ -364,8 +363,8 @@ struct attr_desc mandatory_attr_desc[] =
{
/* PJ_STUN_ATTR_XOR_INTERNAL_ADDR, */
"XOR-INTERNAL-ADDRESS",
- &decode_generic_ip_addr_attr,
- &encode_generic_ip_addr_attr
+ &decode_ip_addr_attr,
+ &encode_ip_addr_attr
},
/* Sentinel */
@@ -382,26 +381,26 @@ static struct attr_desc extended_attr_desc[] =
{
/* PJ_STUN_ATTR_FINGERPRINT, */
"FINGERPRINT",
- &decode_generic_uint_attr,
- &encode_generic_uint_attr
+ &decode_uint_attr,
+ &encode_uint_attr
},
{
/* PJ_STUN_ATTR_SERVER, */
"SERVER",
- &decode_generic_string_attr,
- &encode_generic_string_attr
+ &decode_string_attr,
+ &encode_string_attr
},
{
/* PJ_STUN_ATTR_ALTERNATE_SERVER, */
"ALTERNATE-SERVER",
- &decode_generic_ip_addr_attr,
- &encode_generic_ip_addr_attr
+ &decode_ip_addr_attr,
+ &encode_ip_addr_attr
},
{
/* PJ_STUN_ATTR_REFRESH_INTERVAL, */
"REFRESH-INTERVAL",
- &decode_generic_uint_attr,
- &encode_generic_uint_attr
+ &decode_uint_attr,
+ &encode_uint_attr
},
};
@@ -514,20 +513,20 @@ PJ_DEF(pj_str_t) pj_stun_get_err_reason(int err_code)
* Create a generic STUN IP address attribute for IPv4 address.
*/
PJ_DEF(pj_status_t)
-pj_stun_generic_ip_addr_attr_create(pj_pool_t *pool,
- int attr_type,
- pj_bool_t xor_ed,
- const pj_sockaddr_t *addr,
- unsigned addr_len,
- pj_stun_generic_ip_addr_attr **p_attr)
+pj_stun_ip_addr_attr_create(pj_pool_t *pool,
+ int attr_type,
+ pj_bool_t xor_ed,
+ const pj_sockaddr_t *addr,
+ unsigned addr_len,
+ pj_stun_ip_addr_attr **p_attr)
{
- pj_stun_generic_ip_addr_attr *attr;
+ pj_stun_ip_addr_attr *attr;
PJ_ASSERT_RETURN(pool && addr_len && addr && p_attr, PJ_EINVAL);
PJ_ASSERT_RETURN(addr_len == sizeof(pj_sockaddr_in) ||
addr_len == sizeof(pj_sockaddr_in6), PJ_EINVAL);
- attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_generic_ip_addr_attr);
+ attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_ip_addr_attr);
INIT_ATTR(attr, attr_type, STUN_GENERIC_IP_ADDR_LEN);
if (!xor_ed) {
@@ -555,17 +554,17 @@ pj_stun_generic_ip_addr_attr_create(pj_pool_t *pool,
* Create and add generic STUN IP address attribute to a STUN message.
*/
PJ_DEF(pj_status_t)
-pj_stun_msg_add_generic_ip_addr_attr(pj_pool_t *pool,
- pj_stun_msg *msg,
- int attr_type,
- pj_bool_t xor_ed,
- const pj_sockaddr_t *addr,
- unsigned addr_len)
+pj_stun_msg_add_ip_addr_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int attr_type,
+ pj_bool_t xor_ed,
+ const pj_sockaddr_t *addr,
+ unsigned addr_len)
{
- pj_stun_generic_ip_addr_attr *attr;
+ pj_stun_ip_addr_attr *attr;
pj_status_t status;
- status = pj_stun_generic_ip_addr_attr_create(pool, attr_type, xor_ed,
+ status = pj_stun_ip_addr_attr_create(pool, attr_type, xor_ed,
addr, addr_len, &attr);
if (status != PJ_SUCCESS)
return status;
@@ -573,15 +572,15 @@ pj_stun_msg_add_generic_ip_addr_attr(pj_pool_t *pool,
return pj_stun_msg_add_attr(msg, &attr->hdr);
}
-static pj_status_t decode_generic_ip_addr_attr(pj_pool_t *pool,
- const pj_uint8_t *buf,
- void **p_attr)
+static pj_status_t decode_ip_addr_attr(pj_pool_t *pool,
+ const pj_uint8_t *buf,
+ void **p_attr)
{
- pj_stun_generic_ip_addr_attr *attr;
+ pj_stun_ip_addr_attr *attr;
pj_uint32_t val;
/* Create the attribute */
- attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_generic_ip_addr_attr);
+ attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_ip_addr_attr);
pj_memcpy(attr, buf, ATTR_HDR_LEN);
/* Convert to host byte order */
@@ -611,23 +610,23 @@ static pj_status_t decode_generic_ip_addr_attr(pj_pool_t *pool,
}
-static pj_status_t encode_generic_ip_addr_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed)
+static pj_status_t encode_ip_addr_attr(const void *a, pj_uint8_t *buf,
+ unsigned len, unsigned *printed)
{
enum {
ATTR_LEN = ATTR_HDR_LEN + STUN_GENERIC_IP_ADDR_LEN
};
pj_uint8_t *start_buf = buf;
- const pj_stun_generic_ip_addr_attr *ca =
- (const pj_stun_generic_ip_addr_attr *)a;
- pj_stun_generic_ip_addr_attr *attr;
+ const pj_stun_ip_addr_attr *ca =
+ (const pj_stun_ip_addr_attr *)a;
+ pj_stun_ip_addr_attr *attr;
if (len < ATTR_LEN)
return PJ_ETOOSMALL;
/* Copy and convert headers to network byte order */
pj_memcpy(buf, a, ATTR_HDR_LEN);
- attr = (pj_stun_generic_ip_addr_attr*) buf;
+ attr = (pj_stun_ip_addr_attr*) buf;
attr->hdr.type = pj_htons(attr->hdr.type);
attr->hdr.length = pj_htons((pj_uint16_t)STUN_GENERIC_IP_ADDR_LEN);
buf += ATTR_HDR_LEN;
@@ -665,16 +664,16 @@ static pj_status_t encode_generic_ip_addr_attr(const void *a, pj_uint8_t *buf,
* Create a STUN generic string attribute.
*/
PJ_DEF(pj_status_t)
-pj_stun_generic_string_attr_create(pj_pool_t *pool,
- int attr_type,
- const pj_str_t *value,
- pj_stun_generic_string_attr **p_attr)
+pj_stun_string_attr_create(pj_pool_t *pool,
+ int attr_type,
+ const pj_str_t *value,
+ pj_stun_string_attr **p_attr)
{
- pj_stun_generic_string_attr *attr;
+ pj_stun_string_attr *attr;
PJ_ASSERT_RETURN(pool && value && p_attr, PJ_EINVAL);
- attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_generic_string_attr);
+ attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_string_attr);
INIT_ATTR(attr, attr_type, value->slen);
pj_strdup(pool, &attr->value, value);
@@ -688,15 +687,15 @@ pj_stun_generic_string_attr_create(pj_pool_t *pool,
* Create and add STUN generic string attribute to the message.
*/
PJ_DEF(pj_status_t)
-pj_stun_msg_add_generic_string_attr(pj_pool_t *pool,
- pj_stun_msg *msg,
- int attr_type,
- const pj_str_t *value)
+pj_stun_msg_add_string_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int attr_type,
+ const pj_str_t *value)
{
- pj_stun_generic_string_attr *attr;
+ pj_stun_string_attr *attr;
pj_status_t status;
- status = pj_stun_generic_string_attr_create(pool, attr_type, value,
+ status = pj_stun_string_attr_create(pool, attr_type, value,
&attr);
if (status != PJ_SUCCESS)
return status;
@@ -705,15 +704,15 @@ pj_stun_msg_add_generic_string_attr(pj_pool_t *pool,
}
-static pj_status_t decode_generic_string_attr(pj_pool_t *pool,
- const pj_uint8_t *buf,
- void **p_attr)
+static pj_status_t decode_string_attr(pj_pool_t *pool,
+ const pj_uint8_t *buf,
+ void **p_attr)
{
- pj_stun_generic_string_attr *attr;
+ pj_stun_string_attr *attr;
pj_str_t value;
/* Create the attribute */
- attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_generic_string_attr);
+ attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_string_attr);
/* Copy the header */
pj_memcpy(attr, buf, ATTR_HDR_LEN);
@@ -737,11 +736,11 @@ static pj_status_t decode_generic_string_attr(pj_pool_t *pool,
}
-static pj_status_t encode_generic_string_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed)
+static pj_status_t encode_string_attr(const void *a, pj_uint8_t *buf,
+ unsigned len, unsigned *printed)
{
- const pj_stun_generic_string_attr *ca =
- (const pj_stun_generic_string_attr*)a;
+ const pj_stun_string_attr *ca =
+ (const pj_stun_string_attr*)a;
pj_stun_attr_hdr *attr;
/* Calculated total attr_len (add padding if necessary) */
@@ -856,16 +855,16 @@ static pj_status_t encode_empty_attr(const void *a, pj_uint8_t *buf,
* Create a STUN generic 32bit value attribute.
*/
PJ_DEF(pj_status_t)
-pj_stun_generic_uint_attr_create(pj_pool_t *pool,
- int attr_type,
- pj_uint32_t value,
- pj_stun_generic_uint_attr **p_attr)
+pj_stun_uint_attr_create(pj_pool_t *pool,
+ int attr_type,
+ pj_uint32_t value,
+ pj_stun_uint_attr **p_attr)
{
- pj_stun_generic_uint_attr *attr;
+ pj_stun_uint_attr *attr;
PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL);
- attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_generic_uint_attr);
+ attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_uint_attr);
INIT_ATTR(attr, attr_type, STUN_UINT_LEN);
attr->value = value;
@@ -876,36 +875,36 @@ pj_stun_generic_uint_attr_create(pj_pool_t *pool,
/* Create and add STUN generic 32bit value attribute to the message. */
PJ_DEF(pj_status_t)
-pj_stun_msg_add_generic_uint_attr(pj_pool_t *pool,
- pj_stun_msg *msg,
- int attr_type,
- pj_uint32_t value)
+pj_stun_msg_add_uint_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int attr_type,
+ pj_uint32_t value)
{
- pj_stun_generic_uint_attr *attr;
+ pj_stun_uint_attr *attr;
pj_status_t status;
- status = pj_stun_generic_uint_attr_create(pool, attr_type, value, &attr);
+ status = pj_stun_uint_attr_create(pool, attr_type, value, &attr);
if (status != PJ_SUCCESS)
return status;
return pj_stun_msg_add_attr(msg, &attr->hdr);
}
-static pj_status_t decode_generic_uint_attr(pj_pool_t *pool,
- const pj_uint8_t *buf,
- void **p_attr)
+static pj_status_t decode_uint_attr(pj_pool_t *pool,
+ const pj_uint8_t *buf,
+ void **p_attr)
{
enum
{
ATTR_LEN = STUN_UINT_LEN + ATTR_HDR_LEN
};
- pj_stun_generic_uint_attr *attr;
+ pj_stun_uint_attr *attr;
/* Check that the struct address is valid */
- pj_assert(sizeof(pj_stun_generic_uint_attr) == ATTR_LEN);
+ pj_assert(sizeof(pj_stun_uint_attr) == ATTR_LEN);
/* Create the attribute */
- attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_generic_uint_attr);
+ attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_uint_attr);
pj_memcpy(attr, buf, ATTR_LEN);
/* Convert to host byte order */
@@ -924,21 +923,21 @@ static pj_status_t decode_generic_uint_attr(pj_pool_t *pool,
}
-static pj_status_t encode_generic_uint_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed)
+static pj_status_t encode_uint_attr(const void *a, pj_uint8_t *buf,
+ unsigned len, unsigned *printed)
{
enum
{
ATTR_LEN = STUN_UINT_LEN + ATTR_HDR_LEN
};
- pj_stun_generic_uint_attr *attr;
+ pj_stun_uint_attr *attr;
if (len < ATTR_LEN)
return PJ_ETOOSMALL;
/* Copy and convert attribute to network byte order */
pj_memcpy(buf, a, ATTR_LEN);
- attr = (pj_stun_generic_uint_attr*) buf;
+ attr = (pj_stun_uint_attr*) buf;
attr->hdr.type = pj_htons(attr->hdr.type);
pj_assert(attr->hdr.length == STUN_UINT_LEN);
attr->hdr.length = pj_htons(STUN_UINT_LEN);
@@ -961,14 +960,14 @@ static pj_status_t encode_generic_uint_attr(const void *a, pj_uint8_t *buf,
* Create a STUN MESSAGE-INTEGRITY attribute.
*/
PJ_DEF(pj_status_t)
-pj_stun_msg_integrity_attr_create(pj_pool_t *pool,
- pj_stun_msg_integrity_attr **p_attr)
+pj_stun_msgint_attr_create(pj_pool_t *pool,
+ pj_stun_msgint_attr **p_attr)
{
- pj_stun_msg_integrity_attr *attr;
+ pj_stun_msgint_attr *attr;
PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL);
- attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_msg_integrity_attr);
+ attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_msgint_attr);
INIT_ATTR(attr, PJ_STUN_ATTR_MESSAGE_INTEGRITY, STUN_MSG_INTEGRITY_LEN);
*p_attr = attr;
@@ -977,22 +976,35 @@ pj_stun_msg_integrity_attr_create(pj_pool_t *pool,
}
-static pj_status_t decode_msg_integrity_attr(pj_pool_t *pool,
- const pj_uint8_t *buf,
- void **p_attr)
+PJ_DEF(pj_status_t) pj_stun_msg_add_msgint_attr(pj_pool_t *pool,
+ pj_stun_msg *msg)
+{
+ pj_stun_msgint_attr *attr;
+ pj_status_t status;
+
+ status = pj_stun_msgint_attr_create(pool, &attr);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ return pj_stun_msg_add_attr(msg, &attr->hdr);
+}
+
+static pj_status_t decode_msgint_attr(pj_pool_t *pool,
+ const pj_uint8_t *buf,
+ void **p_attr)
{
enum
{
ATTR_LEN = STUN_MSG_INTEGRITY_LEN + ATTR_HDR_LEN
};
- pj_stun_msg_integrity_attr *attr;
+ pj_stun_msgint_attr *attr;
/* Check that struct size is valid */
- pj_assert(sizeof(pj_stun_msg_integrity_attr)==ATTR_LEN);
+ pj_assert(sizeof(pj_stun_msgint_attr)==ATTR_LEN);
/* Create attribute */
- attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_msg_integrity_attr);
- pj_memcpy(attr, buf, sizeof(pj_stun_msg_integrity_attr));
+ attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_msgint_attr);
+ pj_memcpy(attr, buf, sizeof(pj_stun_msgint_attr));
attr->hdr.type = pj_ntohs(attr->hdr.type);
attr->hdr.length = pj_ntohs(attr->hdr.length);
@@ -1006,21 +1018,21 @@ static pj_status_t decode_msg_integrity_attr(pj_pool_t *pool,
}
-static pj_status_t encode_msg_integrity_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed)
+static pj_status_t encode_msgint_attr(const void *a, pj_uint8_t *buf,
+ unsigned len, unsigned *printed)
{
enum
{
ATTR_LEN = STUN_MSG_INTEGRITY_LEN + ATTR_HDR_LEN
};
- pj_stun_msg_integrity_attr *attr;
+ pj_stun_msgint_attr *attr;
if (len < ATTR_LEN)
return PJ_ETOOSMALL;
/* Copy and convert attribute to network byte order */
pj_memcpy(buf, a, ATTR_LEN);
- attr = (pj_stun_msg_integrity_attr*) buf;
+ attr = (pj_stun_msgint_attr*) buf;
attr->hdr.type = pj_htons(attr->hdr.type);
pj_assert(attr->hdr.length == STUN_MSG_INTEGRITY_LEN);
attr->hdr.length = pj_htons(STUN_MSG_INTEGRITY_LEN);
@@ -1040,12 +1052,12 @@ static pj_status_t encode_msg_integrity_attr(const void *a, pj_uint8_t *buf,
* Create a STUN ERROR-CODE attribute.
*/
PJ_DEF(pj_status_t)
-pj_stun_error_code_attr_create(pj_pool_t *pool,
- int err_code,
- const pj_str_t *err_reason,
- pj_stun_error_code_attr **p_attr)
+pj_stun_errcode_attr_create(pj_pool_t *pool,
+ int err_code,
+ const pj_str_t *err_reason,
+ pj_stun_errcode_attr **p_attr)
{
- pj_stun_error_code_attr *attr;
+ pj_stun_errcode_attr *attr;
char err_buf[80];
pj_str_t str;
@@ -1061,7 +1073,7 @@ pj_stun_error_code_attr_create(pj_pool_t *pool,
err_reason = &str;
}
- attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_error_code_attr);
+ attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_errcode_attr);
INIT_ATTR(attr, PJ_STUN_ATTR_ERROR_CODE, 4+err_reason->slen);
attr->err_class = (pj_uint8_t)(err_code / 100);
attr->number = (pj_uint8_t) (err_code % 100);
@@ -1073,15 +1085,31 @@ pj_stun_error_code_attr_create(pj_pool_t *pool,
}
-static pj_status_t decode_error_code_attr(pj_pool_t *pool,
- const pj_uint8_t *buf,
- void **p_attr)
+PJ_DEF(pj_status_t) pj_stun_msg_add_errcode_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int err_code,
+ const pj_str_t *err_reason)
+{
+ pj_stun_errcode_attr *err_attr;
+ pj_status_t status;
+
+ status = pj_stun_errcode_attr_create(pool, err_code, err_reason,
+ &err_attr);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ return pj_stun_msg_add_attr(msg, &err_attr->hdr);
+}
+
+static pj_status_t decode_errcode_attr(pj_pool_t *pool,
+ const pj_uint8_t *buf,
+ void **p_attr)
{
- pj_stun_error_code_attr *attr;
+ pj_stun_errcode_attr *attr;
pj_str_t value;
/* Create the attribute */
- attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_error_code_attr);
+ attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_errcode_attr);
/* Copy the header */
pj_memcpy(attr, buf, ATTR_HDR_LEN + 4);
@@ -1104,12 +1132,12 @@ static pj_status_t decode_error_code_attr(pj_pool_t *pool,
}
-static pj_status_t encode_error_code_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed)
+static pj_status_t encode_errcode_attr(const void *a, pj_uint8_t *buf,
+ unsigned len, unsigned *printed)
{
- const pj_stun_error_code_attr *ca =
- (const pj_stun_error_code_attr*)a;
- pj_stun_error_code_attr *attr;
+ const pj_stun_errcode_attr *ca =
+ (const pj_stun_errcode_attr*)a;
+ pj_stun_errcode_attr *attr;
if (len < ATTR_HDR_LEN + 4 + (unsigned)ca->reason.slen)
return PJ_ETOOSMALL;
@@ -1118,7 +1146,7 @@ static pj_status_t encode_error_code_attr(const void *a, pj_uint8_t *buf,
pj_memcpy(buf, ca, ATTR_HDR_LEN + 4);
/* Update length */
- attr = (pj_stun_error_code_attr*) buf;
+ attr = (pj_stun_errcode_attr*) buf;
attr->hdr.length = (pj_uint16_t)(4 + ca->reason.slen);
/* Convert fiends to network byte order */
@@ -1507,7 +1535,6 @@ PJ_DEF(pj_status_t) pj_stun_msg_create_response(pj_pool_t *pool,
{
unsigned msg_type = req_msg->hdr.type;
pj_stun_msg *response;
- pj_stun_error_code_attr *err_attr;
pj_status_t status;
PJ_ASSERT_RETURN(pool && p_response, PJ_EINVAL);
@@ -1529,13 +1556,11 @@ PJ_DEF(pj_status_t) pj_stun_msg_create_response(pj_pool_t *pool,
/* Add error code attribute */
if (err_code) {
- status = pj_stun_error_code_attr_create(pool, err_code, err_msg,
- &err_attr);
+ status = pj_stun_msg_add_errcode_attr(pool, response,
+ err_code, err_msg);
if (status != PJ_SUCCESS) {
return status;
}
-
- pj_stun_msg_add_attr(response, &err_attr->hdr);
}
*p_response = response;
@@ -1702,7 +1727,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
PJ_STUN_STATUS_BAD_REQUEST,
NULL, p_response);
}
- return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_BAD_REQUEST);
+ return PJLIB_UTIL_ESTUNDUPATTR;
}
has_msg_int = PJ_TRUE;
@@ -1716,7 +1741,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
PJ_STUN_STATUS_BAD_REQUEST,
NULL, p_response);
}
- return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_BAD_REQUEST);
+ return PJLIB_UTIL_ESTUNDUPATTR;
}
has_fingerprint = PJ_TRUE;
} else {
@@ -1730,7 +1755,8 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
PJ_STUN_STATUS_BAD_REQUEST,
NULL, p_response);
}
- return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_BAD_REQUEST);
+ return has_fingerprint ? PJLIB_UTIL_ESTUNFINGERPOS :
+ PJLIB_UTIL_ESTUNMSGINTPOS;
}
}
@@ -1766,10 +1792,10 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
/* Calculate HMAC-SHA1 key for long term credential, by getting
* MD5 digest of username, realm, and password.
*/
-static void calc_md5_key(pj_uint8_t digest[16],
- const pj_str_t *realm,
- const pj_str_t *username,
- const pj_str_t *passwd)
+void pj_stun_calc_md5_key(pj_uint8_t digest[16],
+ const pj_str_t *realm,
+ const pj_str_t *username,
+ const pj_str_t *passwd)
{
/* The 16-byte key for MESSAGE-INTEGRITY HMAC is formed by taking
* the MD5 hash of the result of concatenating the following five
@@ -1827,7 +1853,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
pj_uint8_t *start = buf;
pj_stun_realm_attr *arealm = NULL;
pj_stun_username_attr *auname = NULL;
- pj_stun_msg_integrity_attr *amsg_integrity = NULL;
+ pj_stun_msgint_attr *amsgint = NULL;
pj_stun_fingerprint_attr *afingerprint = NULL;
unsigned printed;
pj_status_t status;
@@ -1859,8 +1885,8 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
const pj_stun_attr_hdr *attr_hdr = msg->attr[i];
if (attr_hdr->type == PJ_STUN_ATTR_MESSAGE_INTEGRITY) {
- pj_assert(amsg_integrity == NULL);
- amsg_integrity = (pj_stun_msg_integrity_attr*) attr_hdr;
+ pj_assert(amsgint == NULL);
+ amsgint = (pj_stun_msgint_attr*) attr_hdr;
/* Stop when encountering MESSAGE-INTEGRITY */
break;
@@ -1901,9 +1927,9 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
if (attr_hdr->type == PJ_STUN_ATTR_MESSAGE_INTEGRITY) {
/* There mustn't be MESSAGE-INTEGRITY before */
- PJ_ASSERT_RETURN(amsg_integrity == NULL,
+ PJ_ASSERT_RETURN(amsgint == NULL,
PJLIB_UTIL_ESTUNMSGINTPOS);
- amsg_integrity = (pj_stun_msg_integrity_attr*) attr_hdr;
+ amsgint = (pj_stun_msgint_attr*) attr_hdr;
} else if (attr_hdr->type == PJ_STUN_ATTR_FINGERPRINT) {
afingerprint = (pj_stun_fingerprint_attr*) attr_hdr;
@@ -1914,9 +1940,9 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
* calculating MESSAGE-INTEGRITY and FINGERPRINT.
* Note that length is not including the 20 bytes header.
*/
- if (amsg_integrity && afingerprint) {
+ if (amsgint && afingerprint) {
msg->hdr.length = (pj_uint16_t)((buf - start) - 20 + 24 + 8);
- } else if (amsg_integrity) {
+ } else if (amsgint) {
msg->hdr.length = (pj_uint16_t)((buf - start) - 20 + 24);
} else if (afingerprint) {
msg->hdr.length = (pj_uint16_t)((buf - start) - 20 + 8);
@@ -1929,7 +1955,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
start[3] = (pj_uint8_t)(msg->hdr.length & 0x00FF);
/* Calculate message integrity, if present */
- if (amsg_integrity != NULL) {
+ if (amsgint != NULL) {
pj_uint8_t md5_key_buf[16];
pj_str_t key;
@@ -1968,8 +1994,8 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
key = *password;
} else {
- calc_md5_key(md5_key_buf, &arealm->value, &auname->value,
- password);
+ pj_stun_calc_md5_key(md5_key_buf, &arealm->value,
+ &auname->value, password);
key.ptr = (char*) md5_key_buf;
key.slen = 16;
}
@@ -1977,11 +2003,11 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
/* Calculate HMAC-SHA1 digest */
pj_hmac_sha1((pj_uint8_t*)buf, buf-start,
(pj_uint8_t*)key.ptr, key.slen,
- amsg_integrity->hmac);
+ amsgint->hmac);
/* Put this attribute in the message */
- status = encode_msg_integrity_attr(amsg_integrity, buf, buf_size,
- &printed);
+ status = encode_msgint_attr(amsgint, buf, buf_size,
+ &printed);
if (status != PJ_SUCCESS)
return status;
@@ -1995,7 +2021,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
afingerprint->value ^= STUN_XOR_FINGERPRINT;
/* Put this attribute in the message */
- status = encode_generic_uint_attr(afingerprint, buf, buf_size,
+ status = encode_uint_attr(afingerprint, buf, buf_size,
&printed);
if (status != PJ_SUCCESS)
return status;
@@ -2024,296 +2050,9 @@ PJ_DEF(pj_stun_attr_hdr*) pj_stun_msg_find_attr( const pj_stun_msg *msg,
for (; index < msg->attr_count; ++index) {
if (msg->attr[index]->type == attr_type)
- return (pj_stun_attr_hdr*) &msg->attr[index];
+ return (pj_stun_attr_hdr*) msg->attr[index];
}
return NULL;
}
-
-/**************************************************************************/
-/*
- * Authentication
- */
-
-
-/* Send 401 response */
-static pj_status_t create_challenge(pj_pool_t *pool,
- const pj_stun_msg *msg,
- int err_code,
- const pj_str_t *err_msg,
- const pj_str_t *realm,
- const pj_str_t *nonce,
- pj_stun_msg **p_response)
-{
- pj_stun_msg *response;
- pj_status_t rc;
-
- rc = pj_stun_msg_create_response(pool, msg,
- err_code, err_msg, &response);
- if (rc != PJ_SUCCESS)
- return rc;
-
-
- if (realm && realm->slen) {
- rc = pj_stun_msg_add_generic_string_attr(pool, response,
- PJ_STUN_ATTR_REALM,
- realm);
- if (rc != PJ_SUCCESS)
- return rc;
- }
-
- if (nonce && nonce->slen) {
- rc = pj_stun_msg_add_generic_string_attr(pool, response,
- PJ_STUN_ATTR_NONCE,
- nonce);
- if (rc != PJ_SUCCESS)
- return rc;
- }
-
- *p_response = response;
-
- return PJ_SUCCESS;
-}
-
-/* Verify credential */
-PJ_DEF(pj_status_t) pj_stun_verify_credential( const pj_uint8_t *pkt,
- unsigned pkt_len,
- const pj_stun_msg *msg,
- pj_stun_auth_policy *pol,
- pj_pool_t *pool,
- pj_stun_msg **p_response)
-{
- pj_str_t realm, nonce, password;
- const pj_stun_msg_integrity_attr *amsgi;
- unsigned amsgi_pos;
- const pj_stun_username_attr *auser;
- pj_bool_t username_ok;
- const pj_stun_realm_attr *arealm;
- const pj_stun_realm_attr *anonce;
- pj_uint8_t digest[PJ_SHA1_DIGEST_SIZE];
- pj_uint8_t md5_digest[16];
- pj_str_t key;
- pj_status_t status;
-
- /* msg and policy MUST be specified */
- PJ_ASSERT_RETURN(pkt && pkt_len && msg && pol, PJ_EINVAL);
-
- /* If p_response is specified, pool MUST be specified. */
- PJ_ASSERT_RETURN(!p_response || pool, PJ_EINVAL);
-
- if (p_response)
- *p_response = NULL;
-
- if (!PJ_STUN_IS_REQUEST(msg->hdr.type))
- p_response = NULL;
-
- /* Get realm and nonce */
- realm.slen = nonce.slen = 0;
- if (pol->type == PJ_STUN_POLICY_STATIC_SHORT_TERM) {
- realm.slen = 0;
- nonce = pol->data.static_short_term.nonce;
- } else if (pol->type == PJ_STUN_POLICY_STATIC_LONG_TERM) {
- realm = pol->data.static_long_term.realm;
- nonce = pol->data.static_long_term.nonce;
- } else if (pol->type == PJ_STUN_POLICY_DYNAMIC) {
- status = pol->data.dynamic.get_auth(pol->user_data, pool,
- &realm, &nonce);
- if (status != PJ_SUCCESS)
- return status;
- } else {
- pj_assert(!"Unexpected");
- return PJ_EBUG;
- }
-
- /* First check that MESSAGE-INTEGRITY is present */
- amsgi = (const pj_stun_msg_integrity_attr*)
- pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_MESSAGE_INTEGRITY, 0);
- if (amsgi == NULL) {
- if (p_response) {
- create_challenge(pool, msg, PJ_STUN_STATUS_UNAUTHORIZED, NULL,
- &realm, &nonce, p_response);
- }
- return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_UNAUTHORIZED);
- }
-
- /* Next check that USERNAME is present */
- auser = (const pj_stun_username_attr*)
- pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0);
- if (auser == NULL) {
- if (p_response) {
- create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_USERNAME, NULL,
- &realm, &nonce, p_response);
- }
- return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_MISSING_USERNAME);
- }
-
- /* Get REALM, if any */
- arealm = (const pj_stun_realm_attr*)
- pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REALM, 0);
-
- /* Check if username match */
- if (pol->type == PJ_STUN_POLICY_STATIC_SHORT_TERM) {
- username_ok = !pj_strcmp(&auser->value,
- &pol->data.static_short_term.username);
- password = pol->data.static_short_term.password;
- } else if (pol->type == PJ_STUN_POLICY_STATIC_LONG_TERM) {
- username_ok = !pj_strcmp(&auser->value,
- &pol->data.static_long_term.username);
- password = pol->data.static_long_term.password;
- } else if (pol->type == PJ_STUN_POLICY_DYNAMIC) {
- pj_status_t rc;
- rc = pol->data.dynamic.get_password(pol->user_data,
- (arealm?&arealm->value:NULL),
- &auser->value, pool,
- &password);
- username_ok = (rc == PJ_SUCCESS);
- } else {
- username_ok = PJ_TRUE;
- password.slen = 0;
- }
-
- if (!username_ok) {
- /* Username mismatch */
- if (p_response) {
- create_challenge(pool, msg, PJ_STUN_STATUS_UNKNOWN_USERNAME, NULL,
- &realm, &nonce, p_response);
- }
- return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_UNKNOWN_USERNAME);
- }
-
-
- /* Get NONCE attribute */
- anonce = (pj_stun_nonce_attr*)
- pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_NONCE, 0);
-
- /* Check for long term/short term requirements. */
- if (realm.slen != 0 && arealm == NULL) {
- /* Long term credential is required and REALM is not present */
- if (p_response) {
- create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_REALM, NULL,
- &realm, &nonce, p_response);
- }
- return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_MISSING_REALM);
-
- } else if (realm.slen != 0 && arealm != NULL) {
- /* We want long term, and REALM is present */
-
- /* NONCE must be present. */
- if (anonce == NULL) {
- if (p_response) {
- create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_NONCE,
- NULL, &realm, &nonce, p_response);
- }
- return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_MISSING_NONCE);
- }
-
- /* Verify REALM matches */
- if (pj_stricmp(&arealm->value, &realm)) {
- /* REALM doesn't match */
- if (p_response) {
- create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_REALM,
- NULL, &realm, &nonce, p_response);
- }
- return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_MISSING_REALM);
- }
-
- /* Valid case, will validate the message integrity later */
-
- } else if (realm.slen == 0 && arealm != NULL) {
- /* We want to use short term credential, but client uses long
- * term credential. The draft doesn't mention anything about
- * switching between long term and short term.
- */
-
- /* For now just accept the credential, anyway it will probably
- * cause wrong message integrity value later.
- */
- } else if (realm.slen==0 && arealm == NULL) {
- /* Short term authentication is wanted, and one is supplied */
-
- /* Application MAY request NONCE to be supplied */
- if (nonce.slen != 0) {
- if (p_response) {
- create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_NONCE,
- NULL, &realm, &nonce, p_response);
- }
- return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_MISSING_NONCE);
- }
- }
-
- /* If NONCE is present, validate it */
- if (anonce) {
- pj_bool_t ok;
-
- if (pol->type == PJ_STUN_POLICY_DYNAMIC) {
- ok = pol->data.dynamic.verify_nonce(pol->user_data,
- (arealm?&arealm->value:NULL),
- &auser->value,
- &anonce->value);
- } else {
- if (nonce.slen) {
- ok = !pj_strcmp(&anonce->value, &nonce);
- } else {
- ok = PJ_TRUE;
- }
- }
-
- if (!ok) {
- if (p_response) {
- create_challenge(pool, msg, PJ_STUN_STATUS_STALE_NONCE,
- NULL, &realm, &nonce, p_response);
- }
- return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_STALE_NONCE);
- }
- }
-
- /* Get the position of MESSAGE-INTEGRITY in the packet */
- amsgi_pos = 20+msg->hdr.length-22;
- if (GET_VAL16(pkt, amsgi_pos) == PJ_STUN_ATTR_MESSAGE_INTEGRITY) {
- /* Found MESSAGE-INTEGRITY as the last attribute */
- } else {
- amsgi_pos = 0;
- }
-
- if (amsgi_pos==0) {
- amsgi_pos = 20+msg->hdr.length-8-22;
- if (GET_VAL16(pkt, amsgi_pos) == PJ_STUN_ATTR_MESSAGE_INTEGRITY) {
- /* Found MESSAGE-INTEGRITY before FINGERPRINT */
- } else {
- amsgi_pos = 0;
- }
- }
-
- if (amsgi_pos==0) {
- pj_assert(!"Unable to find MESSAGE-INTEGRITY in the message!");
- return PJ_EBUG;
- }
-
- /* Determine which key to use */
- if (realm.slen) {
- calc_md5_key(md5_digest, &realm, &auser->value, &password);
- key.ptr = (char*)md5_digest;
- key.slen = 16;
- } else {
- key = password;
- }
-
- /* Now calculate HMAC of the message */
- pj_hmac_sha1(pkt, amsgi_pos, (pj_uint8_t*)key.ptr, key.slen, digest);
-
- /* Compare HMACs */
- if (pj_memcmp(amsgi->hmac, digest, 20)) {
- /* HMAC value mismatch */
- if (p_response) {
- create_challenge(pool, msg, PJ_STUN_STATUS_INTEGRITY_CHECK_FAILURE,
- NULL, &realm, &nonce, p_response);
- }
- return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_INTEGRITY_CHECK_FAILURE);
- }
-
- /* Everything looks okay! */
- return PJ_SUCCESS;
-}
-
-
diff --git a/pjlib-util/src/pjlib-util/stun_msg_dump.c b/pjlib-util/src/pjlib-util/stun_msg_dump.c
index 21d569da..1c9ccc2e 100644
--- a/pjlib-util/src/pjlib-util/stun_msg_dump.c
+++ b/pjlib-util/src/pjlib-util/stun_msg_dump.c
@@ -53,9 +53,9 @@ static int print_attr(char *buffer, unsigned length,
case PJ_STUN_ATTR_XOR_INTERNAL_ADDR:
case PJ_STUN_ATTR_ALTERNATE_SERVER:
{
- const pj_stun_generic_ip_addr_attr *attr;
+ const pj_stun_ip_addr_attr *attr;
- attr = (const pj_stun_generic_ip_addr_attr*)ahdr;
+ attr = (const pj_stun_ip_addr_attr*)ahdr;
if (attr->addr.addr.sa_family == PJ_AF_INET) {
len = pj_ansi_snprintf(p, end-p,
@@ -84,9 +84,9 @@ static int print_attr(char *buffer, unsigned length,
case PJ_STUN_ATTR_FINGERPRINT:
case PJ_STUN_ATTR_REFRESH_INTERVAL:
{
- const pj_stun_generic_uint_attr *attr;
+ const pj_stun_uint_attr *attr;
- attr = (const pj_stun_generic_uint_attr*)ahdr;
+ attr = (const pj_stun_uint_attr*)ahdr;
len = pj_ansi_snprintf(p, end-p,
", value=%d (0x%x)\n",
(pj_uint32_t)attr->value,
@@ -100,9 +100,9 @@ static int print_attr(char *buffer, unsigned length,
case PJ_STUN_ATTR_NONCE:
case PJ_STUN_ATTR_SERVER:
{
- const pj_stun_generic_string_attr *attr;
+ const pj_stun_string_attr *attr;
- attr = (pj_stun_generic_string_attr*)ahdr;
+ attr = (pj_stun_string_attr*)ahdr;
len = pj_ansi_snprintf(p, end-p,
", value=\"%.*s\"\n",
(int)attr->value.slen,
@@ -112,9 +112,9 @@ static int print_attr(char *buffer, unsigned length,
case PJ_STUN_ATTR_ERROR_CODE:
{
- const pj_stun_error_code_attr *attr;
+ const pj_stun_errcode_attr *attr;
- attr = (const pj_stun_error_code_attr*) ahdr;
+ attr = (const pj_stun_errcode_attr*) ahdr;
len = pj_ansi_snprintf(p, end-p,
", err_code=%d, reason=\"%.*s\"\n",
attr->err_class*100 + attr->number,
diff --git a/pjlib-util/src/pjlib-util/stun_server.c b/pjlib-util/src/pjlib-util/stun_server.c
deleted file mode 100644
index d4d7fa8f..00000000
--- a/pjlib-util/src/pjlib-util/stun_server.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/* $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_server.h>
-#include <pjlib-util/errno.h>
-#include <pj/assert.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-
-
-struct pj_stun_service
-{
- pj_str_t name;
- unsigned options;
- void *user_data;
- unsigned cb_cnt;
- pj_stun_service_handler *cb;
-};
-
-
-/*
- * Create STUN service.
- */
-PJ_DEF(pj_status_t) pj_stun_service_create( pj_pool_t *pool,
- const char *name,
- unsigned options,
- unsigned handler_cnt,
- pj_stun_service_handler cb[],
- void *user_data,
- pj_stun_service **p_svc)
-{
- pj_stun_service *svc;
-
- PJ_ASSERT_RETURN(pool && handler_cnt && cb && p_svc, PJ_EINVAL);
-
- svc = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_service);
- svc->options = options;
- svc->user_data = user_data;
-
- if (!name) name = "pj_stun_service";
-
- pj_strdup2_with_null(pool, &svc->name, name);
-
- svc->cb_cnt = handler_cnt;
- svc->cb = pj_pool_calloc(pool, handler_cnt,
- sizeof(pj_stun_service_handler));
- pj_memcpy(svc->cb, cb, handler_cnt * sizeof(pj_stun_service_handler));
-
- *p_svc = svc;
-
- return PJ_SUCCESS;
-}
-
-
-/*
- * Destroy STUN service
- */
-PJ_DEF(pj_status_t) pj_stun_service_destroy(pj_stun_service *svc)
-{
- PJ_ASSERT_RETURN(svc, PJ_EINVAL);
- return PJ_SUCCESS;
-}
-
-
-/*
- * Get user data associated with the STUN service.
- */
-PJ_DEF(void*) pj_stun_service_get_user_data(pj_stun_service *svc)
-{
- PJ_ASSERT_RETURN(svc, NULL);
- return svc->user_data;
-}
-
-
-/*
- * Find handler.
- */
-static pj_stun_service_handler *find_handler(pj_stun_service *svc,
- int msg_type)
-{
- unsigned i;
-
- for (i=0; i<svc->cb_cnt; ++i) {
- if (svc->cb[i].msg_type == msg_type)
- return &svc->cb[i];
- }
-
- return NULL;
-}
-
-
-/*
- * Instruct the STUN service to handle incoming STUN message.
- */
-PJ_DEF(pj_status_t) pj_stun_service_handle_msg( pj_stun_service *svc,
- void *handle_data,
- const pj_stun_msg *msg)
-{
- pj_stun_service_handler *handler;
-
- PJ_ASSERT_RETURN(svc && msg, PJ_EINVAL);
-
- handler = find_handler(svc, msg->hdr.type);
- if (handler == NULL)
- return PJLIB_UTIL_ESTUNNOHANDLER;
-
- return (*handler->handle_msg)(svc, handle_data, msg);
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-
-
-
diff --git a/pjlib-util/src/pjlib-util/stun_session.c b/pjlib-util/src/pjlib-util/stun_session.c
index 11146047..7ec9d333 100644
--- a/pjlib-util/src/pjlib-util/stun_session.c
+++ b/pjlib-util/src/pjlib-util/stun_session.c
@@ -27,14 +27,9 @@ struct pj_stun_session
pj_stun_session_cb cb;
void *user_data;
- /* Long term credential */
- pj_str_t l_realm;
- pj_str_t l_username;
- pj_str_t l_password;
-
- /* Short term credential */
- pj_str_t s_username;
- pj_str_t s_password;
+ pj_bool_t use_fingerprint;
+ pj_stun_auth_cred *cred;
+ pj_str_t srv_name;
pj_stun_tx_data pending_request_list;
pj_stun_tx_data cached_response_list;
@@ -213,88 +208,65 @@ static void on_cache_timeout(pj_timer_heap_t *timer_heap,
pj_stun_msg_destroy_tdata(tdata->sess, tdata);
}
+static pj_str_t *get_passwd(pj_stun_session *sess)
+{
+ if (sess->cred == NULL)
+ return NULL;
+ else if (sess->cred->type == PJ_STUN_AUTH_CRED_STATIC)
+ return &sess->cred->data.static_cred.data;
+ else
+ return NULL;
+}
+
static pj_status_t apply_msg_options(pj_stun_session *sess,
pj_pool_t *pool,
- unsigned options,
- pj_stun_msg *msg,
- pj_str_t **p_passwd)
+ pj_stun_msg *msg)
{
- pj_status_t status;
+ pj_status_t status = 0;
+
+ /* The server SHOULD include a SERVER attribute in all responses */
+ if (PJ_STUN_IS_RESPONSE(msg->hdr.type) ||
+ PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))
+ {
+ pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SERVER,
+ &sess->srv_name);
+ }
/* From draft-ietf-behave-rfc3489bis-05.txt
* Section 8.3.1. Formulating the Request Message
+ *
+ * Note: only put MESSAGE-INTEGRITY in non error response.
*/
- if (options & PJ_STUN_USE_LONG_TERM_CRED) {
- pj_stun_generic_string_attr *auname;
- pj_stun_msg_integrity_attr *amsgi;
- pj_stun_generic_string_attr *arealm;
-
- *p_passwd = &sess->l_password;
+ if (sess->cred && sess->cred->type == PJ_STUN_AUTH_CRED_STATIC &&
+ !PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))
+ {
+ const pj_str_t *username;
/* Create and add USERNAME attribute */
- status = pj_stun_generic_string_attr_create(pool,
- PJ_STUN_ATTR_USERNAME,
- &sess->l_username,
- &auname);
- PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
-
- status = pj_stun_msg_add_attr(msg, &auname->hdr);
+ username = &sess->cred->data.static_cred.username;
+ status = pj_stun_msg_add_string_attr(pool, msg,
+ PJ_STUN_ATTR_USERNAME,
+ username);
PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
/* Add REALM only when long term credential is used */
- status = pj_stun_generic_string_attr_create(pool,
- PJ_STUN_ATTR_REALM,
- &sess->l_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(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);
-
- } else if (options & PJ_STUN_USE_SHORT_TERM_CRED) {
- pj_stun_generic_string_attr *auname;
- pj_stun_msg_integrity_attr *amsgi;
-
- *p_passwd = &sess->s_password;
-
- /* Create and add USERNAME attribute */
- status = pj_stun_generic_string_attr_create(pool,
- PJ_STUN_ATTR_USERNAME,
- &sess->s_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->cred->data.static_cred.realm.slen) {
+ const pj_str_t *realm = &sess->cred->data.static_cred.realm;
+ status = pj_stun_msg_add_string_attr(pool, msg,
+ PJ_STUN_ATTR_REALM,
+ realm);
+ }
/* Add MESSAGE-INTEGRITY attribute */
- status = pj_stun_msg_integrity_attr_create(pool, &amsgi);
- PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
-
- status = pj_stun_msg_add_attr(msg, &amsgi->hdr);
+ status = pj_stun_msg_add_msgint_attr(pool, msg);
PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
- } else {
- *p_passwd = NULL;
- }
+ }
/* Add FINGERPRINT attribute if necessary */
- if (options & PJ_STUN_USE_FINGERPRINT) {
- pj_stun_fingerprint_attr *af;
-
- status = pj_stun_generic_uint_attr_create(pool,
- PJ_STUN_ATTR_FINGERPRINT,
- 0, &af);
- PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
-
- status = pj_stun_msg_add_attr(msg, &af->hdr);
+ if (sess->use_fingerprint) {
+ status = pj_stun_msg_add_uint_attr(pool, msg,
+ PJ_STUN_ATTR_FINGERPRINT, 0);
PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
}
@@ -333,6 +305,7 @@ static pj_status_t tsx_on_send_msg(pj_stun_client_tsx *tsx,
PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_endpoint *endpt,
const char *name,
const pj_stun_session_cb *cb,
+ pj_bool_t fingerprint,
pj_stun_session **p_sess)
{
pj_pool_t *pool;
@@ -351,6 +324,11 @@ PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_endpoint *endpt,
sess->endpt = endpt;
sess->pool = pool;
pj_memcpy(&sess->cb, cb, sizeof(*cb));
+ sess->use_fingerprint = fingerprint;
+
+ sess->srv_name.ptr = pj_pool_alloc(pool, 32);
+ sess->srv_name.slen = pj_ansi_snprintf(sess->srv_name.ptr, 32,
+ "pj_stun-%s", PJ_VERSION);
pj_list_init(&sess->pending_request_list);
pj_list_init(&sess->cached_response_list);
@@ -393,41 +371,25 @@ PJ_DEF(void*) pj_stun_session_get_user_data(pj_stun_session *sess)
return sess->user_data;
}
-PJ_DEF(pj_status_t)
-pj_stun_session_set_long_term_credential(pj_stun_session *sess,
- const pj_str_t *realm,
- const pj_str_t *user,
- const pj_str_t *passwd)
+PJ_DEF(pj_status_t) pj_stun_session_set_server_name(pj_stun_session *sess,
+ const pj_str_t *srv_name)
{
- pj_str_t nil = { NULL, 0 };
-
- PJ_ASSERT_RETURN(sess, PJ_EINVAL);
-
- pj_mutex_lock(sess->mutex);
- pj_strdup_with_null(sess->pool, &sess->l_realm, realm ? realm : &nil);
- pj_strdup_with_null(sess->pool, &sess->l_username, user ? user : &nil);
- pj_strdup_with_null(sess->pool, &sess->l_password, passwd ? passwd : &nil);
- pj_mutex_unlock(sess->mutex);
-
+ PJ_ASSERT_RETURN(sess && srv_name, PJ_EINVAL);
+ pj_strdup(sess->pool, &sess->srv_name, srv_name);
return PJ_SUCCESS;
}
-
-PJ_DEF(pj_status_t)
-pj_stun_session_set_short_term_credential(pj_stun_session *sess,
- const pj_str_t *user,
- const pj_str_t *passwd)
+PJ_DEF(void) pj_stun_session_set_credential(pj_stun_session *sess,
+ const pj_stun_auth_cred *cred)
{
- pj_str_t nil = { NULL, 0 };
-
- PJ_ASSERT_RETURN(sess, PJ_EINVAL);
-
- pj_mutex_lock(sess->mutex);
- pj_strdup_with_null(sess->pool, &sess->s_username, user ? user : &nil);
- pj_strdup_with_null(sess->pool, &sess->s_password, passwd ? passwd : &nil);
- pj_mutex_unlock(sess->mutex);
-
- return PJ_SUCCESS;
+ PJ_ASSERT_ON_FAIL(sess, return);
+ if (cred) {
+ if (!sess->cred)
+ sess->cred = pj_pool_alloc(sess->pool, sizeof(pj_stun_auth_cred));
+ pj_stun_auth_cred_dup(sess->pool, sess->cred, cred);
+ } else {
+ sess->cred = NULL;
+ }
}
@@ -569,18 +531,15 @@ static void dump_tx_msg(pj_stun_session *sess, const pj_stun_msg *msg,
PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
- unsigned options,
+ pj_bool_t cache_res,
const pj_sockaddr_t *server,
unsigned addr_len,
pj_stun_tx_data *tdata)
{
- pj_str_t *password;
pj_status_t status;
PJ_ASSERT_RETURN(sess && addr_len && server && tdata, PJ_EINVAL);
- tdata->options = options;
-
/* Allocate packet */
tdata->max_len = PJ_STUN_MAX_PKT_LEN;
tdata->pkt = pj_pool_alloc(tdata->pool, tdata->max_len);
@@ -589,8 +548,7 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
pj_mutex_lock(sess->mutex);
/* Apply options */
- status = apply_msg_options(sess, tdata->pool, options,
- tdata->msg, &password);
+ status = apply_msg_options(sess, tdata->pool, tdata->msg);
if (status != PJ_SUCCESS) {
pj_stun_msg_destroy_tdata(sess, tdata);
pj_mutex_unlock(sess->mutex);
@@ -600,7 +558,7 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
/* Encode message */
status = pj_stun_msg_encode(tdata->msg, tdata->pkt, tdata->max_len,
- 0, password, &tdata->pkt_size);
+ 0, get_passwd(sess), &tdata->pkt_size);
if (status != PJ_SUCCESS) {
pj_stun_msg_destroy_tdata(sess, tdata);
pj_mutex_unlock(sess->mutex);
@@ -640,7 +598,7 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
tsx_add(sess, tdata);
} else {
- if ((options & PJ_STUN_CACHE_RESPONSE) &&
+ if (cache_res &&
(PJ_STUN_IS_RESPONSE(tdata->msg->hdr.type) ||
PJ_STUN_IS_ERROR_RESPONSE(tdata->msg->hdr.type)))
{
@@ -687,6 +645,68 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
}
+/* Send response */
+static pj_status_t send_response(pj_stun_session *sess,
+ pj_pool_t *pool, pj_stun_msg *response,
+ pj_bool_t retransmission,
+ const pj_sockaddr_t *addr, unsigned addr_len)
+{
+ pj_uint8_t *out_pkt;
+ unsigned out_max_len, out_len;
+ pj_status_t status;
+
+ /* Alloc packet buffer */
+ out_max_len = PJ_STUN_MAX_PKT_LEN;
+ out_pkt = pj_pool_alloc(pool, out_max_len);
+
+ /* Apply options */
+ if (!retransmission) {
+ apply_msg_options(sess, pool, response);
+ }
+
+ /* Encode */
+ status = pj_stun_msg_encode(response, out_pkt, out_max_len, 0,
+ get_passwd(sess), &out_len);
+ if (status != PJ_SUCCESS) {
+ LOG_ERR_(sess, "Error encoding message", status);
+ return status;
+ }
+
+ /* Print log */
+ dump_tx_msg(sess, response, out_len, addr);
+
+ /* Send packet */
+ status = sess->cb.on_send_msg(sess, out_pkt, out_len, addr, addr_len);
+
+ return status;
+}
+
+/* Authenticate incoming message */
+static pj_status_t authenticate_msg(pj_stun_session *sess,
+ const pj_uint8_t *pkt,
+ unsigned pkt_len,
+ const pj_stun_msg *msg,
+ pj_pool_t *tmp_pool,
+ const pj_sockaddr_t *src_addr,
+ unsigned src_addr_len)
+{
+ pj_stun_msg *response;
+ pj_status_t status;
+
+ if (PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type) || sess->cred == NULL)
+ return PJ_SUCCESS;
+
+ status = pj_stun_verify_credential(pkt, pkt_len, msg, sess->cred,
+ tmp_pool, &response);
+ if (status != PJ_SUCCESS && response != NULL) {
+ send_response(sess, tmp_pool, response, PJ_FALSE,
+ src_addr, src_addr_len);
+ }
+
+ return status;
+}
+
+
/* Handle incoming response */
static pj_status_t on_incoming_response(pj_stun_session *sess,
pj_stun_msg *msg)
@@ -723,51 +743,14 @@ static pj_status_t on_incoming_response(pj_stun_session *sess,
}
-/* Send response */
-static pj_status_t send_response(pj_stun_session *sess, unsigned options,
- pj_pool_t *pool, pj_stun_msg *response,
- const pj_sockaddr_t *addr, unsigned addr_len)
-{
- pj_uint8_t *out_pkt;
- unsigned out_max_len, out_len;
- pj_str_t *passwd;
- pj_status_t status;
-
- /* Alloc packet buffer */
- out_max_len = PJ_STUN_MAX_PKT_LEN;
- out_pkt = pj_pool_alloc(pool, out_max_len);
-
- /* Apply options */
- apply_msg_options(sess, pool, options, response, &passwd);
-
- /* Encode */
- status = pj_stun_msg_encode(response, out_pkt, out_max_len, 0,
- passwd, &out_len);
- if (status != PJ_SUCCESS) {
- LOG_ERR_(sess, "Error encoding message", status);
- return status;
- }
-
- /* Print log */
- dump_tx_msg(sess, response, out_len, addr);
-
- /* Send packet */
- status = sess->cb.on_send_msg(sess, out_pkt, out_len, addr, addr_len);
-
- return status;
-}
-
-/* Handle incoming request */
-static pj_status_t on_incoming_request(pj_stun_session *sess,
- pj_pool_t *tmp_pool,
- const pj_uint8_t *in_pkt,
- unsigned in_pkt_len,
- const pj_stun_msg *msg,
- const pj_sockaddr_t *src_addr,
- unsigned src_addr_len)
+/* For requests, check if we cache the response */
+static pj_status_t check_cached_response(pj_stun_session *sess,
+ pj_pool_t *tmp_pool,
+ const pj_stun_msg *msg,
+ const pj_sockaddr_t *src_addr,
+ unsigned src_addr_len)
{
pj_stun_tx_data *t;
- pj_status_t status;
/* First lookup response in response cache */
t = sess->cached_response_list.next;
@@ -783,30 +766,42 @@ static pj_status_t on_incoming_request(pj_stun_session *sess,
if (t != &sess->cached_response_list) {
/* Found response in the cache */
- unsigned options;
PJ_LOG(5,(SNAME(sess),
"Request retransmission, sending cached response"));
- options = t->options;
- options &= ~PJ_STUN_CACHE_RESPONSE;
- pj_stun_session_send_msg(sess, options, src_addr, src_addr_len, t);
+ send_response(sess, tmp_pool, t->msg, PJ_TRUE,
+ src_addr, src_addr_len);
return PJ_SUCCESS;
}
+ return PJ_ENOTFOUND;
+}
+
+/* Handle incoming request */
+static pj_status_t on_incoming_request(pj_stun_session *sess,
+ pj_pool_t *tmp_pool,
+ const pj_uint8_t *in_pkt,
+ unsigned in_pkt_len,
+ const pj_stun_msg *msg,
+ const pj_sockaddr_t *src_addr,
+ unsigned src_addr_len)
+{
+ pj_status_t status;
+
/* Distribute to handler, or respond with Bad Request */
if (sess->cb.on_rx_request) {
status = (*sess->cb.on_rx_request)(sess, in_pkt, in_pkt_len, msg,
src_addr, src_addr_len);
} else {
- pj_stun_msg *response = NULL;
+ pj_stun_msg *response;
status = pj_stun_msg_create_response(tmp_pool, msg,
PJ_STUN_STATUS_BAD_REQUEST, NULL,
&response);
if (status == PJ_SUCCESS && response) {
- status = send_response(sess, 0, tmp_pool, response,
- src_addr, src_addr_len);
+ status = send_response(sess, tmp_pool, response,
+ PJ_FALSE, src_addr, src_addr_len);
}
}
@@ -861,8 +856,8 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
if (status != PJ_SUCCESS) {
LOG_ERR_(sess, "STUN msg_decode() error", status);
if (response) {
- send_response(sess, 0, tmp_pool, response,
- src_addr, src_addr_len);
+ send_response(sess, tmp_pool, response,
+ PJ_FALSE, src_addr, src_addr_len);
}
pj_pool_release(tmp_pool);
return status;
@@ -879,6 +874,20 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
pj_mutex_lock(sess->mutex);
+ /* For requests, check if we have cached response */
+ status = check_cached_response(sess, tmp_pool, msg,
+ src_addr, src_addr_len);
+ if (status == PJ_SUCCESS) {
+ goto on_return;
+ }
+
+ /* Authenticate the message */
+ status = authenticate_msg(sess, packet, pkt_size, msg, tmp_pool,
+ src_addr, src_addr_len);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+
+ /* Handle message */
if (PJ_STUN_IS_RESPONSE(msg->hdr.type) ||
PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))
{
@@ -899,6 +908,7 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
status = PJ_EBUG;
}
+on_return:
pj_mutex_unlock(sess->mutex);
pj_pool_release(tmp_pool);
diff --git a/pjlib-util/src/pjlib-util/stun_transaction.c b/pjlib-util/src/pjlib-util/stun_transaction.c
index 02f33177..636d56d1 100644
--- a/pjlib-util/src/pjlib-util/stun_transaction.c
+++ b/pjlib-util/src/pjlib-util/stun_transaction.c
@@ -259,7 +259,7 @@ static void retransmit_timer_callback(pj_timer_heap_t *timer_heap,
PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx,
const pj_stun_msg *msg)
{
- pj_stun_error_code_attr *err_attr;
+ pj_stun_errcode_attr *err_attr;
pj_status_t status;
/* Must be STUN response message */
@@ -281,7 +281,7 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx,
}
/* Find STUN error code attribute */
- err_attr = (pj_stun_error_code_attr*)
+ err_attr = (pj_stun_errcode_attr*)
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ERROR_CODE, 0);
if (err_attr && err_attr->err_class <= 2) {
@@ -300,8 +300,7 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx,
if (err_attr == NULL) {
status = PJ_SUCCESS;
} else {
- status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_class * 100 +
- err_attr->number);
+ status = PJLIB_UTIL_ESTUNTSXFAILED;
}
/* Call callback */
diff --git a/pjlib-util/src/pjstun-client/client_main.c b/pjlib-util/src/pjstun-client/client_main.c
index 4f82f743..fd1b9e39 100644
--- a/pjlib-util/src/pjstun-client/client_main.c
+++ b/pjlib-util/src/pjstun-client/client_main.c
@@ -29,7 +29,6 @@ static struct global
pj_caching_pool cp;
pj_timer_heap_t *th;
pj_stun_session *sess;
- unsigned sess_options;
pj_sock_t sock;
pj_thread_t *thread;
pj_bool_t quit;
@@ -45,6 +44,7 @@ static struct options
char *realm;
char *user_name;
char *password;
+ char *nonce;
pj_bool_t use_fingerprint;
} o;
@@ -180,40 +180,28 @@ static int init()
stun_cb.on_send_msg = &on_send_msg;
stun_cb.on_request_complete = &on_request_complete;
- status = pj_stun_session_create(g.endpt, NULL, &stun_cb, &g.sess);
+ status = pj_stun_session_create(g.endpt, NULL, &stun_cb,
+ o.use_fingerprint!=0, &g.sess);
pj_assert(status == PJ_SUCCESS);
- if (o.realm) {
- pj_str_t r, u, p;
+ if (o.user_name) {
+ pj_stun_auth_cred cred;
- if (o.user_name == NULL) {
- printf("error: username must be specified\n");
- return PJ_EINVAL;
- }
- if (o.password == NULL)
- o.password = "";
- g.sess_options = PJ_STUN_USE_LONG_TERM_CRED;
- pj_stun_session_set_long_term_credential(g.sess, pj_cstr(&r, o.realm),
- pj_cstr(&u, o.user_name),
- pj_cstr(&p, o.password));
- puts("Using long term credential");
- } else if (o.user_name) {
- pj_str_t u, p;
-
- if (o.password == NULL)
- o.password = "";
- g.sess_options = PJ_STUN_USE_SHORT_TERM_CRED;
- pj_stun_session_set_short_term_credential(g.sess,
- pj_cstr(&u, o.user_name),
- pj_cstr(&p, o.password));
- puts("Using short term credential");
+ pj_bzero(&cred, sizeof(cred));
+
+ cred.type = PJ_STUN_AUTH_CRED_STATIC;
+ cred.data.static_cred.realm = pj_str(o.realm);
+ cred.data.static_cred.username = pj_str(o.user_name);
+ cred.data.static_cred.data_type = 0;
+ cred.data.static_cred.data = pj_str(o.password);
+ cred.data.static_cred.nonce = pj_str(o.nonce);
+
+ pj_stun_session_set_credential(g.sess, &cred);
+ puts("Session credential set");
} else {
puts("Credential not set");
}
- if (o.use_fingerprint)
- g.sess_options |= PJ_STUN_USE_FINGERPRINT;
-
status = pj_thread_create(g.pool, "stun", &worker_thread, NULL,
0, 0, &g.thread);
if (status != PJ_SUCCESS)
@@ -275,7 +263,7 @@ static void console_main(void)
rc = pj_stun_session_create_bind_req(g.sess, &tdata);
pj_assert(rc == PJ_SUCCESS);
- rc = pj_stun_session_send_msg(g.sess, g.sess_options,
+ rc = pj_stun_session_send_msg(g.sess, PJ_FALSE,
&g.dst_addr, sizeof(g.dst_addr),
tdata);
if (rc != PJ_SUCCESS)
@@ -302,6 +290,7 @@ static void usage(void)
puts(" --realm, -r Set realm of the credential");
puts(" --username, -u Set username of the credential");
puts(" --password, -p Set password of the credential");
+ puts(" --nonce, -N Set NONCE");
puts(" --fingerprint, -F Use fingerprint for outgoing requests");
puts(" --help, -h");
}
@@ -312,6 +301,7 @@ int main(int argc, char *argv[])
{ "realm", 1, 0, 'r'},
{ "username", 1, 0, 'u'},
{ "password", 1, 0, 'p'},
+ { "nonce", 1, 0, 'N'},
{ "fingerprint",0, 0, 'F'},
{ "help", 0, 0, 'h'}
};
@@ -330,6 +320,9 @@ int main(int argc, char *argv[])
case 'p':
o.password = pj_optarg;
break;
+ case 'N':
+ o.nonce = pj_optarg;
+ break;
case 'h':
usage();
return 0;
diff --git a/pjlib-util/src/pjstun-srv-test/server_main.c b/pjlib-util/src/pjstun-srv-test/server_main.c
index 4825cf8e..e4fc6d5b 100644
--- a/pjlib-util/src/pjstun-srv-test/server_main.c
+++ b/pjlib-util/src/pjstun-srv-test/server_main.c
@@ -61,8 +61,17 @@ static struct stun_server
unsigned thread_cnt;
pj_thread_t *threads[16];
+
} server;
+static struct options
+{
+ char *realm;
+ char *user_name;
+ char *password;
+ char *nonce;
+ pj_bool_t use_fingerprint;
+} o;
static pj_status_t server_perror(const char *sender, const char *title,
pj_status_t status)
@@ -131,10 +140,10 @@ static pj_status_t on_rx_binding_request(pj_stun_session *sess,
return status;
/* Create MAPPED-ADDRESS attribute */
- status = pj_stun_msg_add_generic_ip_addr_attr(tdata->pool, tdata->msg,
- PJ_STUN_ATTR_MAPPED_ADDR,
- PJ_FALSE,
- src_addr, src_addr_len);
+ status = pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg,
+ PJ_STUN_ATTR_MAPPED_ADDR,
+ PJ_FALSE,
+ src_addr, src_addr_len);
if (status != PJ_SUCCESS) {
server_perror(THIS_FILE, "Error creating response", status);
pj_stun_msg_destroy_tdata(sess, tdata);
@@ -144,10 +153,10 @@ static pj_status_t on_rx_binding_request(pj_stun_session *sess,
/* On the presence of magic, create XOR-MAPPED-ADDRESS attribute */
if (msg->hdr.magic == PJ_STUN_MAGIC) {
status =
- pj_stun_msg_add_generic_ip_addr_attr(tdata->pool, tdata->msg,
- PJ_STUN_ATTR_XOR_MAPPED_ADDRESS,
- PJ_TRUE,
- src_addr, src_addr_len);
+ pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg,
+ PJ_STUN_ATTR_XOR_MAPPED_ADDRESS,
+ PJ_TRUE,
+ src_addr, src_addr_len);
if (status != PJ_SUCCESS) {
server_perror(THIS_FILE, "Error creating response", status);
pj_stun_msg_destroy_tdata(sess, tdata);
@@ -156,7 +165,7 @@ static pj_status_t on_rx_binding_request(pj_stun_session *sess,
}
/* Send */
- status = pj_stun_session_send_msg(sess, PJ_STUN_CACHE_RESPONSE,
+ status = pj_stun_session_send_msg(sess, PJ_TRUE,
src_addr, src_addr_len, tdata);
return status;
}
@@ -263,12 +272,32 @@ static pj_status_t init_service(struct service *svc)
sess_cb.on_send_msg = &on_send_msg;
sess_cb.on_rx_request = &on_rx_request;
status = pj_stun_session_create(server.endpt, "session",
- &sess_cb, &svc->sess);
+ &sess_cb,
+ o.use_fingerprint!=0,
+ &svc->sess);
if (status != PJ_SUCCESS)
goto on_error;
pj_stun_session_set_user_data(svc->sess, (void*)svc);
+ if (o.user_name) {
+ pj_stun_auth_cred cred;
+
+ pj_bzero(&cred, sizeof(cred));
+
+ cred.type = PJ_STUN_AUTH_CRED_STATIC;
+ cred.data.static_cred.realm = pj_str(o.realm);
+ cred.data.static_cred.username = pj_str(o.user_name);
+ cred.data.static_cred.data_type = 0;
+ cred.data.static_cred.data = pj_str(o.password);
+ cred.data.static_cred.nonce = pj_str(o.nonce);
+
+ pj_stun_session_set_credential(svc->sess, &cred);
+ puts("Session credential set");
+ } else {
+ puts("Credential not set");
+ }
+
pj_bzero(&service_callback, sizeof(service_callback));
service_callback.on_read_complete = &on_read_complete;
@@ -437,8 +466,65 @@ pj_status_t server_destroy(void)
}
-int main()
+static void usage(void)
+{
+ puts("Usage: pjstun_srv_test [OPTIONS]");
+ puts("");
+ puts("where OPTIONS:");
+ puts(" --realm, -r Set realm of the credential");
+ puts(" --username, -u Set username of the credential");
+ puts(" --password, -p Set password of the credential");
+ puts(" --nonce, -N Set NONCE");
+ puts(" --fingerprint, -F Use fingerprint for outgoing requests");
+ puts(" --help, -h");
+}
+
+
+int main(int argc, char *argv[])
{
+ struct pj_getopt_option long_options[] = {
+ { "realm", 1, 0, 'r'},
+ { "username", 1, 0, 'u'},
+ { "password", 1, 0, 'p'},
+ { "nonce", 1, 0, 'N'},
+ { "fingerprint",0, 0, 'F'},
+ { "help", 0, 0, 'h'}
+ };
+ int c, opt_id;
+
+ while((c=pj_getopt_long(argc,argv, "r:u:p:hF", long_options, &opt_id))!=-1) {
+ switch (c) {
+ case 'r':
+ o.realm = pj_optarg;
+ break;
+ case 'u':
+ o.user_name = pj_optarg;
+ break;
+ case 'p':
+ o.password = pj_optarg;
+ break;
+ case 'N':
+ o.nonce = pj_optarg;
+ break;
+ case 'h':
+ usage();
+ return 0;
+ case 'F':
+ o.use_fingerprint = PJ_TRUE;
+ break;
+ default:
+ printf("Argument \"%s\" is not valid. Use -h to see help",
+ argv[pj_optind]);
+ return 1;
+ }
+ }
+
+ if (pj_optind != argc) {
+ puts("Error: invalid arguments");
+ return 1;
+ }
+
+
if (server_init()) {
server_destroy();
return 1;