Index: pjproject/trunk/pjlib-util/build/pjlib_util.dsp
===================================================================
--- pjproject/trunk/pjlib-util/build/pjlib_util.dsp	(revision 1036)
+++ pjproject/trunk/pjlib-util/build/pjlib_util.dsp	(revision 1037)
@@ -146,4 +146,8 @@
 # Begin Source File
 
+SOURCE="..\src\pjlib-util\stun_auth.c"
+# End Source File
+# Begin Source File
+
 SOURCE="..\src\pjlib-util\stun_endpoint.c"
 # End Source File
@@ -155,8 +159,4 @@
 
 SOURCE="..\src\pjlib-util\stun_msg_dump.c"
-# End Source File
-# Begin Source File
-
-SOURCE="..\src\pjlib-util\stun_server.c"
 # End Source File
 # Begin Source File
@@ -250,4 +250,8 @@
 # Begin Source File
 
+SOURCE="..\include\pjlib-util\stun_auth.h"
+# End Source File
+# Begin Source File
+
 SOURCE="..\include\pjlib-util\stun_doc.h"
 # End Source File
@@ -259,8 +263,4 @@
 
 SOURCE="..\include\pjlib-util\stun_msg.h"
-# End Source File
-# Begin Source File
-
-SOURCE="..\include\pjlib-util\stun_server.h"
 # End Source File
 # Begin Source File
Index: pjproject/trunk/pjlib-util/build/pjlib_util.vcproj
===================================================================
--- pjproject/trunk/pjlib-util/build/pjlib_util.vcproj	(revision 1036)
+++ pjproject/trunk/pjlib-util/build/pjlib_util.vcproj	(revision 1037)
@@ -416,4 +416,8 @@
 			</File>
 			<File
+				RelativePath="..\src\pjlib-util\stun_auth.c"
+				>
+			</File>
+			<File
 				RelativePath="..\src\pjlib-util\stun_endpoint.c"
 				>
@@ -428,5 +432,5 @@
 			</File>
 			<File
-				RelativePath="..\src\pjlib-util\stun_server.c"
+				RelativePath="..\src\pjlib-util\stun_session.c"
 				>
 			</File>
@@ -553,4 +557,8 @@
 			</File>
 			<File
+				RelativePath="..\include\pjlib-util\stun_auth.h"
+				>
+			</File>
+			<File
 				RelativePath="..\include\pjlib-util\stun_doc.h"
 				>
@@ -565,5 +573,5 @@
 			</File>
 			<File
-				RelativePath="..\include\pjlib-util\stun_server.h"
+				RelativePath="..\include\pjlib-util\stun_session.h"
 				>
 			</File>
Index: pjproject/trunk/pjlib-util/build/pjstun_srv_test.dsp
===================================================================
--- pjproject/trunk/pjlib-util/build/pjstun_srv_test.dsp	(revision 1036)
+++ pjproject/trunk/pjlib-util/build/pjstun_srv_test.dsp	(revision 1037)
@@ -94,8 +94,4 @@
 
 # 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"
Index: pjproject/trunk/pjlib-util/include/pjlib-util.h
===================================================================
--- pjproject/trunk/pjlib-util/include/pjlib-util.h	(revision 1036)
+++ pjproject/trunk/pjlib-util/include/pjlib-util.h	(revision 1037)
@@ -50,7 +50,7 @@
 
 /* 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>
Index: pjproject/trunk/pjlib-util/include/pjlib-util/errno.h
===================================================================
--- pjproject/trunk/pjlib-util/include/pjlib-util/errno.h	(revision 1036)
+++ pjproject/trunk/pjlib-util/include/pjlib-util/errno.h	(revision 1037)
@@ -262,22 +262,18 @@
 /**
  * @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 */
-/**
- * @hideinitializer
- * Unknown STUN attribute.
- */
-#define PJLIB_UTIL_ESTUNUNKNOWNATTR (PJLIB_UTIL_ERRNO_START+112)/* 320112 */
+#define PJLIB_UTIL_ESTUNTOOMANYATTR (PJLIB_UTIL_ERRNO_START+110)/* 320110 */
+/**
+ * @hideinitializer
+ * 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+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
@@ -320,7 +316,37 @@
  */
 #define PJLIB_UTIL_ESTUNNOUSERNAME  (PJLIB_UTIL_ERRNO_START+120)/* 320120 */
-
-
-#define PJ_STATUS_FROM_STUN_CODE(code)	(PJLIB_UTIL_ERRNO_START+code)
+/**
+ * @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)
 
 
Index: pjproject/trunk/pjlib-util/include/pjlib-util/stun_auth.h
===================================================================
--- pjproject/trunk/pjlib-util/include/pjlib-util/stun_auth.h	(revision 1037)
+++ pjproject/trunk/pjlib-util/include/pjlib-util/stun_auth.h	(revision 1037)
@@ -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__ */
+
Index: pjproject/trunk/pjlib-util/include/pjlib-util/stun_msg.h
===================================================================
--- pjproject/trunk/pjlib-util/include/pjlib-util/stun_msg.h	(revision 1036)
+++ pjproject/trunk/pjlib-util/include/pjlib-util/stun_msg.h	(revision 1037)
@@ -511,5 +511,5 @@
    \endverbatim
  */
-typedef struct pj_stun_generic_ip_addr_attr
+typedef struct pj_stun_ip_addr_attr
 {
     /**
@@ -527,5 +527,5 @@
     } addr;
 
-} pj_stun_generic_ip_addr_attr;
+} pj_stun_ip_addr_attr;
 
 
@@ -549,5 +549,5 @@
  * NONCE attributes, the text MUST be quoted with.
  */
-typedef struct pj_stun_generic_string_attr
+typedef struct pj_stun_string_attr
 {
     /**
@@ -561,5 +561,5 @@
     pj_str_t		value;
 
-} pj_stun_generic_string_attr;
+} pj_stun_string_attr;
 
 
@@ -568,5 +568,5 @@
  * integer value, such as STUN FINGERPRINT and REFRESH-INTERVAL attributes.
  */
-typedef struct pj_stun_generic_uint_attr
+typedef struct pj_stun_uint_attr
 {
     /**
@@ -580,5 +580,5 @@
     pj_uint32_t		value;
 
-} pj_stun_generic_uint_attr;
+} pj_stun_uint_attr;
 
 
@@ -614,5 +614,5 @@
  * bytes.
  */
-typedef struct pj_stun_msg_integrity_attr
+typedef struct pj_stun_msgint_attr
 {
     /**
@@ -626,5 +626,5 @@
     pj_uint8_t		hmac[20];
 
-} pj_stun_msg_integrity_attr;
+} pj_stun_msgint_attr;
 
 
@@ -635,5 +635,5 @@
  * 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;
 
 
@@ -656,5 +656,5 @@
  \endverbatim
  */
-typedef struct pj_stun_error_code_attr
+typedef struct pj_stun_errcode_attr
 {
     /**
@@ -683,5 +683,5 @@
     pj_str_t		reason;
 
-} pj_stun_error_code_attr;
+} pj_stun_errcode_attr;
 
 
@@ -693,5 +693,5 @@
  * quotes).
  */
-typedef struct pj_stun_generic_string_attr pj_stun_realm_attr;
+typedef struct pj_stun_string_attr pj_stun_realm_attr;
 
 
@@ -703,5 +703,5 @@
  * 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;
 
 
@@ -740,5 +740,5 @@
  * 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;
 
 
@@ -752,5 +752,5 @@
  * 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;
 
 
@@ -763,5 +763,5 @@
  * 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;
 
 
@@ -772,5 +772,5 @@
  * 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;
 
 
@@ -781,5 +781,5 @@
  * 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;
 
 
@@ -793,5 +793,5 @@
  * 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;
 
 
@@ -808,5 +808,5 @@
  * 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;
 
 
@@ -828,5 +828,5 @@
  * 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;
 
 /**
@@ -840,5 +840,5 @@
  * 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;
 
 
@@ -852,5 +852,5 @@
  * 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;
 
 
@@ -862,5 +862,5 @@
  * MESSAGE-INTEGRITY attribute.
  */
-typedef struct pj_stun_generic_string_attr pj_stun_username_attr;
+typedef struct pj_stun_string_attr pj_stun_username_attr;
 
 
@@ -870,5 +870,5 @@
  * PASSWORD attribute.
  */
-typedef struct pj_stun_generic_string_attr pj_stun_password_attr;
+typedef struct pj_stun_string_attr pj_stun_password_attr;
 
 
@@ -880,5 +880,5 @@
  * 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;
 
 
@@ -889,5 +889,5 @@
  * 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;
 
 
@@ -897,5 +897,5 @@
  * 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;
 
 
@@ -915,5 +915,5 @@
  * 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;
 
 
@@ -934,5 +934,5 @@
  \endverbatim
  */
-typedef struct pj_stun_generic_uint_attr pj_stun_requested_addr_type;
+typedef struct pj_stun_uint_attr pj_stun_requested_addr_type;
 
 /**
@@ -954,5 +954,5 @@
  \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;
 
 
@@ -963,5 +963,5 @@
  * 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;
 
 
@@ -971,5 +971,5 @@
  * 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;
 
 /**
@@ -983,5 +983,5 @@
  * 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;
 
 /**
@@ -992,5 +992,5 @@
  * type of 0x0024.
  */
-typedef struct pj_stun_generic_uint_attr pj_stun_priority_attr;
+typedef struct pj_stun_uint_attr pj_stun_priority_attr;
 
 /**
@@ -1011,5 +1011,5 @@
  * 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;
 
 /**
@@ -1019,5 +1019,5 @@
  * 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;
 
 
@@ -1048,5 +1048,5 @@
 
 /** STUN decoding options */
-enum pj_stun_options
+enum pj_stun_decode_options
 {
     /** 
@@ -1063,4 +1063,5 @@
     PJ_STUN_CHECK_PACKET    = 2
 };
+
 
 /**
@@ -1208,13 +1209,13 @@
  * @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);
 
 
@@ -1225,5 +1226,5 @@
  * @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
@@ -1248,136 +1249,4 @@
 				        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.
@@ -1431,11 +1300,10 @@
  * @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);
 
 
@@ -1455,11 +1323,10 @@
  * @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);
 
 /**
@@ -1473,9 +1340,8 @@
  * @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);
 
 /**
@@ -1489,9 +1355,8 @@
  * @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);
 
 /**
@@ -1505,9 +1370,8 @@
  * @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);
 
 /**
@@ -1521,9 +1385,8 @@
  * @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);
 
 
@@ -1536,7 +1399,17 @@
  * @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);
 
 /**
@@ -1551,10 +1424,25 @@
  * @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);
 
 /**
@@ -1569,9 +1457,8 @@
  * @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);
 
 /**
@@ -1585,9 +1472,8 @@
  * @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[]);
 
 /**
@@ -1604,10 +1490,9 @@
  * @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);
 
 /**
@@ -1625,10 +1510,9 @@
  * @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);
 
 
Index: pjproject/trunk/pjlib-util/include/pjlib-util/stun_server.h
===================================================================
--- pjproject/trunk/pjlib-util/include/pjlib-util/stun_server.h	(revision 1036)
+++ 	(revision )
@@ -1,109 +1,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__ */
-
Index: pjproject/trunk/pjlib-util/include/pjlib-util/stun_session.h
===================================================================
--- pjproject/trunk/pjlib-util/include/pjlib-util/stun_session.h	(revision 1036)
+++ pjproject/trunk/pjlib-util/include/pjlib-util/stun_session.h	(revision 1037)
@@ -21,4 +21,5 @@
 
 #include <pjlib-util/stun_msg.h>
+#include <pjlib-util/stun_auth.h>
 #include <pjlib-util/stun_endpoint.h>
 #include <pjlib-util/stun_transaction.h>
@@ -148,5 +149,4 @@
     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.	    */
@@ -157,44 +157,12 @@
 
 /**
- * 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.
@@ -203,4 +171,5 @@
 					    const char *name,
 					    const pj_stun_session_cb *cb,
+					    pj_bool_t fingerprint,
 					    pj_stun_session **p_sess);
 
@@ -236,40 +205,30 @@
 
 /**
- * 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.
- *
- * @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.
- *
- * @return	    PJ_SUCCESS on success, or the appropriate error code.
- */
-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);
-
-
-/**
- * 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.
- *
- * @param sess	    The STUN session instance.
- * @param user	    The user name.
- * @param passwd    The pain-text password.
- *
- * @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);
-
+ * Set server name to be included in all response.
+ *
+ * @param sess	    The STUN session instance.
+ * @param srv_name  Server name string.
+ *
+ * @return	    The user data associated with this STUN session.
+ */
+PJ_DECL(pj_status_t) pj_stun_session_set_server_name(pj_stun_session *sess,
+						     const pj_str_t *srv_name);
+
+/**
+ * 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 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(void) pj_stun_session_set_credential(pj_stun_session *sess,
+					     const pj_stun_auth_cred *cred);
 
 /**
@@ -410,5 +369,5 @@
  *
  * @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.
@@ -419,5 +378,5 @@
  */
 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,
Index: pjproject/trunk/pjlib-util/src/pjlib-util/errno.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjlib-util/errno.c	(revision 1036)
+++ pjproject/trunk/pjlib-util/src/pjlib-util/errno.c	(revision 1037)
@@ -69,4 +69,21 @@
     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 */
Index: pjproject/trunk/pjlib-util/src/pjlib-util/stun_auth.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjlib-util/stun_auth.c	(revision 1037)
+++ pjproject/trunk/pjlib-util/src/pjlib-util/stun_auth.c	(revision 1037)
@@ -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;
+}
+
+
Index: pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg.c	(revision 1036)
+++ pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg.c	(revision 1037)
@@ -22,5 +22,4 @@
 #include <pjlib-util/hmac_sha1.h>
 #include <pjlib-util/md5.h>
-#include <pjlib-util/sha1.h>
 #include <pj/assert.h>
 #include <pj/log.h>
@@ -89,25 +88,25 @@
 };
 
-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, 
@@ -115,9 +114,9 @@
 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,
@@ -143,54 +142,54 @@
 	/* 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
     },
     {
@@ -203,6 +202,6 @@
 	/* 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
     },
     {
@@ -215,6 +214,6 @@
 	/* PJ_STUN_ATTR_LIFETIME, */
 	"LIFETIME",
-	&decode_generic_uint_attr,
-	&encode_generic_uint_attr
+	&decode_uint_attr,
+	&encode_uint_attr
     },
     {
@@ -233,6 +232,6 @@
 	/* PJ_STUN_ATTR_BANDWIDTH, */
 	"BANDWIDTH",
-	&decode_generic_uint_attr,
-	&encode_generic_uint_attr
+	&decode_uint_attr,
+	&encode_uint_attr
     },
     {
@@ -245,6 +244,6 @@
 	/* 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
     },
     {
@@ -257,36 +256,36 @@
 	/* 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
     },
     {
@@ -329,30 +328,30 @@
 	/* 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
     },
     {
@@ -365,6 +364,6 @@
 	/* 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
     },
 
@@ -383,24 +382,24 @@
 	/* 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
     },
 };
@@ -515,12 +514,12 @@
  */
 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_generic_ip_addr_attr *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_ip_addr_attr *attr;
 
     PJ_ASSERT_RETURN(pool && addr_len && addr && p_attr, PJ_EINVAL);
@@ -528,5 +527,5 @@
 		     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);
 
@@ -556,15 +555,15 @@
  */
 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_generic_ip_addr_attr *attr;
+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_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)
@@ -574,13 +573,13 @@
 }
 
-static pj_status_t decode_generic_ip_addr_attr(pj_pool_t *pool, 
-					       const pj_uint8_t *buf, 
-					       void **p_attr)
-{
-    pj_stun_generic_ip_addr_attr *attr;
+static pj_status_t decode_ip_addr_attr(pj_pool_t *pool, 
+				       const pj_uint8_t *buf, 
+				       void **p_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);
 
@@ -612,6 +611,6 @@
 
 
-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 {
@@ -619,7 +618,7 @@
     };
     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) 
@@ -628,5 +627,5 @@
     /* 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);
@@ -666,14 +665,14 @@
  */
 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_generic_string_attr *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_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);
@@ -689,13 +688,13 @@
  */
 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_generic_string_attr *attr;
+pj_stun_msg_add_string_attr(pj_pool_t *pool,
+			    pj_stun_msg *msg,
+			    int attr_type,
+			    const pj_str_t *value)
+{
+    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)
@@ -706,13 +705,13 @@
 
 
-static pj_status_t decode_generic_string_attr(pj_pool_t *pool, 
-					      const pj_uint8_t *buf, 
-					      void **p_attr)
-{
-    pj_stun_generic_string_attr *attr;
+static pj_status_t decode_string_attr(pj_pool_t *pool, 
+				      const pj_uint8_t *buf, 
+				      void **p_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 */
@@ -738,9 +737,9 @@
 
 
-static pj_status_t encode_generic_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;
+static pj_status_t encode_string_attr(const void *a, pj_uint8_t *buf, 
+				      unsigned len, unsigned *printed)
+{
+    const pj_stun_string_attr *ca = 
+	(const pj_stun_string_attr*)a;
     pj_stun_attr_hdr *attr;
 
@@ -857,14 +856,14 @@
  */
 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_generic_uint_attr *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_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;
@@ -877,13 +876,13 @@
 /* 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_generic_uint_attr *attr;
+pj_stun_msg_add_uint_attr(pj_pool_t *pool,
+			  pj_stun_msg *msg,
+			  int attr_type,
+			  pj_uint32_t value)
+{
+    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;
@@ -892,7 +891,7 @@
 }
 
-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
@@ -900,11 +899,11 @@
 	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);
 
@@ -925,6 +924,6 @@
 
 
-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
@@ -932,5 +931,5 @@
 	ATTR_LEN = STUN_UINT_LEN + ATTR_HDR_LEN
     };
-    pj_stun_generic_uint_attr *attr;
+    pj_stun_uint_attr *attr;
 
     if (len < ATTR_LEN) 
@@ -939,5 +938,5 @@
     /* 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);
@@ -962,12 +961,12 @@
  */
 PJ_DEF(pj_status_t) 
-pj_stun_msg_integrity_attr_create(pj_pool_t *pool,
-				  pj_stun_msg_integrity_attr **p_attr)
-{
-    pj_stun_msg_integrity_attr *attr;
+pj_stun_msgint_attr_create(pj_pool_t *pool,
+			   pj_stun_msgint_attr **p_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);
 
@@ -978,7 +977,20 @@
 
 
-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
@@ -986,12 +998,12 @@
 	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);
@@ -1007,6 +1019,6 @@
 
 
-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
@@ -1014,5 +1026,5 @@
 	ATTR_LEN = STUN_MSG_INTEGRITY_LEN + ATTR_HDR_LEN
     };
-    pj_stun_msg_integrity_attr *attr;
+    pj_stun_msgint_attr *attr;
 
     if (len < ATTR_LEN) 
@@ -1021,5 +1033,5 @@
     /* 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);
@@ -1041,10 +1053,10 @@
  */
 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_error_code_attr *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_errcode_attr *attr;
     char err_buf[80];
     pj_str_t str;
@@ -1062,5 +1074,5 @@
     }
 
-    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);
@@ -1074,13 +1086,29 @@
 
 
-static pj_status_t decode_error_code_attr(pj_pool_t *pool, 
-					  const pj_uint8_t *buf,
-					  void **p_attr)
-{
-    pj_stun_error_code_attr *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_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 */
@@ -1105,10 +1133,10 @@
 
 
-static pj_status_t encode_error_code_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;
+static pj_status_t encode_errcode_attr(const void *a, pj_uint8_t *buf, 
+				       unsigned len, unsigned *printed)
+{
+    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) 
@@ -1119,5 +1147,5 @@
 
     /* 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);
 
@@ -1508,5 +1536,4 @@
     unsigned msg_type = req_msg->hdr.type;
     pj_stun_msg *response;
-    pj_stun_error_code_attr *err_attr;
     pj_status_t status;
 
@@ -1530,11 +1557,9 @@
     /* 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);
     }
 
@@ -1703,5 +1728,5 @@
 						    NULL, p_response);
 		    }
-		    return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_BAD_REQUEST);
+		    return PJLIB_UTIL_ESTUNDUPATTR;
 		}
 		has_msg_int = PJ_TRUE;
@@ -1717,5 +1742,5 @@
 						    NULL, p_response);
 		    }
-		    return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_BAD_REQUEST);
+		    return PJLIB_UTIL_ESTUNDUPATTR;
 		}
 		has_fingerprint = PJ_TRUE;
@@ -1731,5 +1756,6 @@
 						    NULL, p_response);
 		    }
-		    return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_BAD_REQUEST);
+		    return has_fingerprint ? PJLIB_UTIL_ESTUNFINGERPOS :
+					     PJLIB_UTIL_ESTUNMSGINTPOS;
 		}
 	    }
@@ -1767,8 +1793,8 @@
  * 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
@@ -1828,5 +1854,5 @@
     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;
@@ -1860,6 +1886,6 @@
 
 	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 */
@@ -1902,7 +1928,7 @@
 	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) {
@@ -1915,7 +1941,7 @@
      * 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) {
@@ -1930,5 +1956,5 @@
 
     /* Calculate message integrity, if present */
-    if (amsg_integrity != NULL) {
+    if (amsgint != NULL) {
 
 	pj_uint8_t md5_key_buf[16];
@@ -1969,6 +1995,6 @@
 
 	} 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;
@@ -1978,9 +2004,9 @@
 	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;
@@ -1996,5 +2022,5 @@
 
 	/* 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)
@@ -2025,5 +2051,5 @@
     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];
     }
 
@@ -2031,289 +2057,2 @@
 }
 
-
-/**************************************************************************/
-/*
- * 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;
-}
-
-
Index: pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg_dump.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg_dump.c	(revision 1036)
+++ pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg_dump.c	(revision 1037)
@@ -54,7 +54,7 @@
     case PJ_STUN_ATTR_ALTERNATE_SERVER:
 	{
-	    const pj_stun_generic_ip_addr_attr *attr;
-
-	    attr = (const pj_stun_generic_ip_addr_attr*)ahdr;
+	    const pj_stun_ip_addr_attr *attr;
+
+	    attr = (const pj_stun_ip_addr_attr*)ahdr;
 
 	    if (attr->addr.addr.sa_family == PJ_AF_INET) {
@@ -85,7 +85,7 @@
     case PJ_STUN_ATTR_REFRESH_INTERVAL:
 	{
-	    const pj_stun_generic_uint_attr *attr;
-
-	    attr = (const pj_stun_generic_uint_attr*)ahdr;
+	    const pj_stun_uint_attr *attr;
+
+	    attr = (const pj_stun_uint_attr*)ahdr;
 	    len = pj_ansi_snprintf(p, end-p,
 				   ", value=%d (0x%x)\n",
@@ -101,7 +101,7 @@
     case PJ_STUN_ATTR_SERVER:
 	{
-	    const pj_stun_generic_string_attr *attr;
-
-	    attr = (pj_stun_generic_string_attr*)ahdr;
+	    const pj_stun_string_attr *attr;
+
+	    attr = (pj_stun_string_attr*)ahdr;
 	    len = pj_ansi_snprintf(p, end-p,
 				   ", value=\"%.*s\"\n",
@@ -113,7 +113,7 @@
     case PJ_STUN_ATTR_ERROR_CODE:
 	{
-	    const pj_stun_error_code_attr *attr;
-
-	    attr = (const pj_stun_error_code_attr*) ahdr;
+	    const pj_stun_errcode_attr *attr;
+
+	    attr = (const pj_stun_errcode_attr*) ahdr;
 	    len = pj_ansi_snprintf(p, end-p,
 				   ", err_code=%d, reason=\"%.*s\"\n",
Index: pjproject/trunk/pjlib-util/src/pjlib-util/stun_server.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjlib-util/stun_server.c	(revision 1036)
+++ 	(revision )
@@ -1,129 +1,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);
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-
-
-
Index: pjproject/trunk/pjlib-util/src/pjlib-util/stun_session.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjlib-util/stun_session.c	(revision 1036)
+++ pjproject/trunk/pjlib-util/src/pjlib-util/stun_session.c	(revision 1037)
@@ -28,12 +28,7 @@
     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;
@@ -214,86 +209,63 @@
 }
 
+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_status_t status;
+				     pj_stun_msg *msg)
+{
+    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);
+	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);
 
-	status = pj_stun_msg_add_attr(msg, &auname->hdr);
+	/* Add REALM only when long term credential is used */
+	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_add_msgint_attr(pool, msg);
 	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);
-
-	/* 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 {
-	*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);
     }
@@ -334,4 +306,5 @@
 					    const char *name,
 					    const pj_stun_session_cb *cb,
+					    pj_bool_t fingerprint,
 					    pj_stun_session **p_sess)
 {
@@ -352,4 +325,9 @@
     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);
@@ -394,39 +372,23 @@
 }
 
-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_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);
-
-    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_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_DEF(pj_status_t) pj_stun_session_set_server_name(pj_stun_session *sess,
+						    const pj_str_t *srv_name)
+{
+    PJ_ASSERT_RETURN(sess && srv_name, PJ_EINVAL);
+    pj_strdup(sess->pool, &sess->srv_name, srv_name);
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(void) pj_stun_session_set_credential(pj_stun_session *sess,
+					    const pj_stun_auth_cred *cred)
+{
+    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;
+    }
 }
 
@@ -570,15 +532,12 @@
 
 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 */
@@ -590,6 +549,5 @@
 
     /* 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);
@@ -601,5 +559,5 @@
     /* 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);
@@ -641,5 +599,5 @@
 
     } 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))) 
@@ -688,4 +646,66 @@
 
 
+/* 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,
@@ -724,49 +744,12 @@
 
 
-/* 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 */
@@ -784,14 +767,26 @@
     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 */
@@ -800,5 +795,5 @@
 					   src_addr, src_addr_len);
     } else {
-	pj_stun_msg *response = NULL;
+	pj_stun_msg *response;
 
 	status = pj_stun_msg_create_response(tmp_pool, msg, 
@@ -806,6 +801,6 @@
 					     &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);
 	}
     }
@@ -862,6 +857,6 @@
 	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);
@@ -880,4 +875,18 @@
     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))
@@ -900,4 +909,5 @@
     }
 
+on_return:
     pj_mutex_unlock(sess->mutex);
 
Index: pjproject/trunk/pjlib-util/src/pjlib-util/stun_transaction.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjlib-util/stun_transaction.c	(revision 1036)
+++ pjproject/trunk/pjlib-util/src/pjlib-util/stun_transaction.c	(revision 1037)
@@ -260,5 +260,5 @@
 						 const pj_stun_msg *msg)
 {
-    pj_stun_error_code_attr *err_attr;
+    pj_stun_errcode_attr *err_attr;
     pj_status_t status;
 
@@ -282,5 +282,5 @@
 
     /* 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);
 
@@ -301,6 +301,5 @@
 	status = PJ_SUCCESS;
     } else {
-	status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_class * 100 +
-					  err_attr->number);
+	status = PJLIB_UTIL_ESTUNTSXFAILED;
     }
 
Index: pjproject/trunk/pjlib-util/src/pjstun-client/client_main.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjstun-client/client_main.c	(revision 1036)
+++ pjproject/trunk/pjlib-util/src/pjstun-client/client_main.c	(revision 1037)
@@ -30,5 +30,4 @@
     pj_timer_heap_t	*th;
     pj_stun_session	*sess;
-    unsigned		 sess_options;
     pj_sock_t		 sock;
     pj_thread_t		*thread;
@@ -46,4 +45,5 @@
     char    *user_name;
     char    *password;
+    char    *nonce;
     pj_bool_t use_fingerprint;
 } o;
@@ -181,37 +181,25 @@
     stun_cb.on_request_complete = &on_request_complete;
 
-    status = pj_stun_session_create(g.endpt, NULL, &stun_cb, &g.sess);
-    pj_assert(status == PJ_SUCCESS);
-
-    if (o.realm) {
-	pj_str_t r, u, p;
-
-	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");
+    status = pj_stun_session_create(g.endpt, NULL, &stun_cb, 
+				    o.use_fingerprint!=0, &g.sess);
+    pj_assert(status == PJ_SUCCESS);
+
+    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(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, 
@@ -276,5 +264,5 @@
 		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);
@@ -303,4 +291,5 @@
     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");
@@ -313,4 +302,5 @@
 	{ "username",	1, 0, 'u'},
 	{ "password",	1, 0, 'p'},
+	{ "nonce",	1, 0, 'N'},
 	{ "fingerprint",0, 0, 'F'},
 	{ "help",	0, 0, 'h'}
@@ -331,4 +321,7 @@
 	    o.password = pj_optarg;
 	    break;
+	case 'N':
+	    o.nonce = pj_optarg;
+	    break;
 	case 'h':
 	    usage();
Index: pjproject/trunk/pjlib-util/src/pjstun-srv-test/server_main.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjstun-srv-test/server_main.c	(revision 1036)
+++ pjproject/trunk/pjlib-util/src/pjstun-srv-test/server_main.c	(revision 1037)
@@ -62,6 +62,15 @@
     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, 
@@ -132,8 +141,8 @@
 
     /* 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);
@@ -145,8 +154,8 @@
     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);
@@ -157,5 +166,5 @@
 
     /* 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;
@@ -264,9 +273,29 @@
     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));
@@ -438,6 +467,63 @@
 
 
-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();
