summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-05-15 10:42:56 +0000
committerBenny Prijono <bennylp@teluu.com>2007-05-15 10:42:56 +0000
commit240fa9cd6f0ede43211b799f4706df92c62a5be9 (patch)
tree6769c97345b1eabb6ebd39a6cb1c76056975957f
parent5406b158f07e67aab413b407d589920f2e120b4a (diff)
Fixed several STUN bugs: USERNAME, REALM etc are not allowed in the response, retransmission timer calculation bug, etc.
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1275 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjnath/include/pjnath/config.h16
-rw-r--r--pjnath/include/pjnath/stun_auth.h50
-rw-r--r--pjnath/include/pjnath/stun_config.h2
-rw-r--r--pjnath/include/pjnath/stun_msg.h60
-rw-r--r--pjnath/include/pjnath/stun_session.h12
-rw-r--r--pjnath/src/pjnath/ice_session.c20
-rw-r--r--pjnath/src/pjnath/stun_auth.c105
-rw-r--r--pjnath/src/pjnath/stun_msg.c110
-rw-r--r--pjnath/src/pjnath/stun_session.c136
-rw-r--r--pjnath/src/pjnath/stun_transaction.c15
-rw-r--r--pjnath/src/pjstun-client/client_main.c15
-rw-r--r--pjnath/src/pjstun-srv-test/bind_usage.c2
-rw-r--r--pjnath/src/pjstun-srv-test/main.c17
-rw-r--r--pjnath/src/pjstun-srv-test/server.h2
-rw-r--r--pjnath/src/pjstun-srv-test/turn_usage.c37
-rw-r--r--third_party/build/Makefile2
-rw-r--r--third_party/build/os-auto.mak.in1
17 files changed, 395 insertions, 207 deletions
diff --git a/pjnath/include/pjnath/config.h b/pjnath/include/pjnath/config.h
index f7cb3009..3b24b944 100644
--- a/pjnath/include/pjnath/config.h
+++ b/pjnath/include/pjnath/config.h
@@ -88,12 +88,22 @@
/**
- * Maximum number of STUN retransmission count.
+ * Maximum number of STUN transmission count.
*
* Default: 7 (as per RFC 3489-bis)
*/
-#ifndef PJ_STUN_MAX_RETRANSMIT_COUNT
-# define PJ_STUN_MAX_RETRANSMIT_COUNT 7
+#ifndef PJ_STUN_MAX_TRANSMIT_COUNT
+# define PJ_STUN_MAX_TRANSMIT_COUNT 7
+#endif
+
+
+/**
+ * Duration to keep response in the cache, in msec.
+ *
+ * Default: 10000 (as per RFC 3489-bis)
+ */
+#ifndef PJ_STUN_RES_CACHE_DURATION
+# define PJ_STUN_RES_CACHE_DURATION 10000
#endif
diff --git a/pjnath/include/pjnath/stun_auth.h b/pjnath/include/pjnath/stun_auth.h
index 539c8867..2bf190d8 100644
--- a/pjnath/include/pjnath/stun_auth.h
+++ b/pjnath/include/pjnath/stun_auth.h
@@ -262,7 +262,7 @@ PJ_DECL(void) pj_stun_auth_cred_dup(pj_pool_t *pool,
/**
- * Verify credential in the STUN message. Note that before calling this
+ * Verify credential in the STUN request. 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
@@ -286,35 +286,41 @@ PJ_DECL(void) pj_stun_auth_cred_dup(pj_pool_t *pool,
* 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);
-
-
+PJ_DECL(pj_status_t) pj_stun_authenticate_request(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);
/**
- * @}
+ * Verify credential in the STUN response. 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 otherwise this function will report authentication
+ * failure.
+ *
+ * @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 key Authentication key to calculate MESSAGE-INTEGRITY
+ * value. Application can create this key by using
+ * #pj_stun_create_key() function.
+ *
+ * @return PJ_SUCCESS if credential is verified successfully.
*/
+PJ_DECL(pj_status_t) pj_stun_authenticate_response(const pj_uint8_t *pkt,
+ unsigned pkt_len,
+ const pj_stun_msg *msg,
+ const pj_str_t *key);
/**
- * Calculate HMAC-SHA1 key for long term credential, by getting
- * MD5 digest of username, realm, and password.
- *
- * @param digest The buffer for the digest.
- * @param realm The realm of the credential, if long term credential
- * is to be used.
- * @param username The username.
- * @param passwd The clear text 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
diff --git a/pjnath/include/pjnath/stun_config.h b/pjnath/include/pjnath/stun_config.h
index d0914267..6a487be8 100644
--- a/pjnath/include/pjnath/stun_config.h
+++ b/pjnath/include/pjnath/stun_config.h
@@ -98,7 +98,7 @@ PJ_INLINE(void) pj_stun_config_init(pj_stun_config *cfg,
cfg->ioqueue = ioqueue;
cfg->timer_heap = timer_heap;
cfg->rto_msec = PJ_STUN_RTO_VALUE;
- cfg->res_cache_msec = 10000;
+ cfg->res_cache_msec = PJ_STUN_RES_CACHE_DURATION;
}
diff --git a/pjnath/include/pjnath/stun_msg.h b/pjnath/include/pjnath/stun_msg.h
index 7234884b..5f04ba59 100644
--- a/pjnath/include/pjnath/stun_msg.h
+++ b/pjnath/include/pjnath/stun_msg.h
@@ -132,13 +132,11 @@ enum pj_stun_msg_class_e
*/
#define PJ_STUN_IS_REQUEST(msg_type) (((msg_type) & 0x0110) == 0x0000)
-
/**
- * Determine if the message type is a response.
+ * Determine if the message type is a successful response.
*/
#define PJ_STUN_IS_SUCCESS_RESPONSE(msg_type) (((msg_type) & 0x0110) == 0x0100)
-
/**
* The response bit in the message type.
*/
@@ -149,12 +147,15 @@ enum pj_stun_msg_class_e
*/
#define PJ_STUN_IS_ERROR_RESPONSE(msg_type) (((msg_type) & 0x0110) == 0x0110)
-
/**
* The error response bit in the message type.
*/
#define PJ_STUN_ERROR_RESPONSE_BIT (0x0110)
+/**
+ * Determine if the message type is a response.
+ */
+#define PJ_STUN_IS_RESPONSE(msg_type) (((msg_type) & 0x0100) == 0x0100)
/**
* Determine if the message type is an indication message.
@@ -1148,17 +1149,20 @@ PJ_DECL(pj_status_t) pj_stun_msg_add_attr(pj_stun_msg *msg,
* Print the STUN message structure to a packet buffer, ready to be
* sent to remote destination. This function will take care about
* calculating the MESSAGE-INTEGRITY digest as well as FINGERPRINT
- * value.
+ * value, if these attributes are present in the message.
*
- * If MESSAGE-INTEGRITY attribute is present, the function assumes
- * that application wants to include credential (short or long term)
- * in the message, and this function will calculate the HMAC digest
- * from the message using the supplied password in the parameter.
- * If REALM attribute is present, the HMAC digest is calculated as
- * long term credential, otherwise as short term credential.
+ * If application wants to apply credential to the message, it MUST
+ * include a blank MESSAGE-INTEGRITY attribute in the message, as the
+ * last attribute or the attribute before FINGERPRINT. This function will
+ * calculate the HMAC digest from the message using the supplied key in
+ * the parameter. The key should be set to the password if short term
+ * credential is used, or calculated from the MD5 hash of the realm,
+ * username, and password using #pj_stun_create_key() if long term
+ * credential is used.
*
* If FINGERPRINT attribute is present, this function will calculate
- * the FINGERPRINT CRC attribute for the message.
+ * the FINGERPRINT CRC attribute for the message. The FINGERPRINT MUST
+ * be added as the last attribute of the message.
*
* @param msg The STUN message to be printed. Upon return,
* some fields in the header (such as message
@@ -1166,9 +1170,9 @@ PJ_DECL(pj_status_t) pj_stun_msg_add_attr(pj_stun_msg *msg,
* @param pkt_buf The buffer to be filled with the packet.
* @param buf_size Size of the buffer.
* @param options Options, which currently must be zero.
- * @param password Password to be used when credential is to be
- * included. This parameter MUST be specified when
- * the message contains MESSAGE-INTEGRITY attribute.
+ * @param key Authentication key to calculate MESSAGE-INTEGRITY
+ * value. Application can create this key by using
+ * #pj_stun_create_key() function.
* @param p_msg_len Upon return, it will be filed with the size of
* the packet in bytes, or negative value on error.
*
@@ -1178,9 +1182,33 @@ PJ_DECL(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
pj_uint8_t *pkt_buf,
unsigned buf_size,
unsigned options,
- const pj_str_t *password,
+ const pj_str_t *key,
unsigned *p_msg_len);
+
+/**
+ * Create authentication key to be used for encoding the message with
+ * MESSAGE-INTEGRITY. If short term credential is used (i.e. the realm
+ * argument is NULL or empty), the key will be copied from the password.
+ * If long term credential is used, the key will be calculated from the
+ * MD5 hash of the realm, username, and password.
+ *
+ * @param pool Pool to allocate memory for the key.
+ * @param key String to receive the key.
+ * @param realm The realm of the credential, if long term credential
+ * is to be used. If short term credential is wanted,
+ * application can put NULL or empty string here.
+ * @param username The username.
+ * @param passwd The clear text password.
+ */
+PJ_DECL(void) pj_stun_create_key(pj_pool_t *pool,
+ pj_str_t *key,
+ const pj_str_t *realm,
+ const pj_str_t *username,
+ const pj_str_t *passwd);
+
+
+
/**
* Check that the PDU is potentially a valid STUN message. This function
* is useful when application needs to multiplex STUN packets with other
diff --git a/pjnath/include/pjnath/stun_session.h b/pjnath/include/pjnath/stun_session.h
index dfbf61c0..8a399a42 100644
--- a/pjnath/include/pjnath/stun_session.h
+++ b/pjnath/include/pjnath/stun_session.h
@@ -161,6 +161,8 @@ struct pj_stun_tx_data
pj_uint32_t msg_magic; /**< Message magic. */
pj_uint8_t msg_key[12]; /**< Message/transaction key. */
+ pj_str_t auth_key; /**< Auth key. */
+
void *pkt; /**< The STUN packet. */
unsigned max_len; /**< Length of packet buffer. */
unsigned pkt_size; /**< The actual length of STUN pkt. */
@@ -305,11 +307,11 @@ PJ_DECL(pj_status_t) pj_stun_session_create_ind(pj_stun_session *sess,
*
* @return PJ_SUCCESS on success, or the appropriate error code.
*/
-PJ_DECL(pj_status_t) pj_stun_session_create_response(pj_stun_session *sess,
- const pj_stun_msg *req,
- unsigned err_code,
- const pj_str_t *err_msg,
- pj_stun_tx_data **p_tdata);
+PJ_DECL(pj_status_t) pj_stun_session_create_res(pj_stun_session *sess,
+ const pj_stun_msg *req,
+ unsigned err_code,
+ const pj_str_t *err_msg,
+ pj_stun_tx_data **p_tdata);
/**
diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c
index 085227dd..246e4564 100644
--- a/pjnath/src/pjnath/ice_session.c
+++ b/pjnath/src/pjnath/ice_session.c
@@ -1869,9 +1869,9 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
/* Reject any requests except Binding request */
if (msg->hdr.type != PJ_STUN_BINDING_REQUEST) {
- status = pj_stun_session_create_response(sess, msg,
- PJ_STUN_SC_BAD_REQUEST,
- NULL, &tdata);
+ status = pj_stun_session_create_res(sess, msg,
+ PJ_STUN_SC_BAD_REQUEST,
+ NULL, &tdata);
if (status != PJ_SUCCESS)
return status;
@@ -1927,9 +1927,9 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
pj_ice_sess_change_role(ice, PJ_ICE_SESS_ROLE_CONTROLLED);
} else {
/* Generate 487 response */
- status = pj_stun_session_create_response(sess, msg,
- PJ_STUN_SC_ROLE_CONFLICT,
- NULL, &tdata);
+ status = pj_stun_session_create_res(sess, msg,
+ PJ_STUN_SC_ROLE_CONFLICT,
+ NULL, &tdata);
if (status == PJ_SUCCESS) {
pj_stun_session_send_msg(sess, PJ_TRUE,
src_addr, src_addr_len, tdata);
@@ -1943,9 +1943,9 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
{
if (pj_cmp_timestamp(&ice->tie_breaker, &role_attr->value) < 0) {
/* Generate 487 response */
- status = pj_stun_session_create_response(sess, msg,
- PJ_STUN_SC_ROLE_CONFLICT,
- NULL, &tdata);
+ status = pj_stun_session_create_res(sess, msg,
+ PJ_STUN_SC_ROLE_CONFLICT,
+ NULL, &tdata);
if (status == PJ_SUCCESS) {
pj_stun_session_send_msg(sess, PJ_TRUE,
src_addr, src_addr_len, tdata);
@@ -1976,7 +1976,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
/*
* First send response to this request
*/
- status = pj_stun_session_create_response(sess, msg, 0, NULL, &tdata);
+ status = pj_stun_session_create_res(sess, msg, 0, NULL, &tdata);
if (status != PJ_SUCCESS) {
pj_mutex_unlock(ice->mutex);
return status;
diff --git a/pjnath/src/pjnath/stun_auth.c b/pjnath/src/pjnath/stun_auth.c
index d49b4fa2..c670bfcd 100644
--- a/pjnath/src/pjnath/stun_auth.c
+++ b/pjnath/src/pjnath/stun_auth.c
@@ -104,13 +104,13 @@ static pj_status_t create_challenge(pj_pool_t *pool,
}
-/* 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)
+/* Verify credential in the request */
+PJ_DEF(pj_status_t) pj_stun_authenticate_request(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;
@@ -121,7 +121,6 @@ PJ_DEF(pj_status_t) pj_stun_verify_credential( const pj_uint8_t *pkt,
const pj_stun_realm_attr *anonce;
pj_hmac_sha1_context ctx;
pj_uint8_t digest[PJ_SHA1_DIGEST_SIZE];
- pj_uint8_t md5_digest[16];
pj_str_t key;
pj_status_t status;
@@ -224,7 +223,7 @@ PJ_DEF(pj_status_t) pj_stun_verify_credential( const pj_uint8_t *pkt,
/* We want long term, and REALM is present */
/* NONCE must be present. */
- if (anonce == NULL) {
+ if (anonce == NULL && nonce.slen) {
if (p_response) {
create_challenge(pool, msg, PJ_STUN_SC_MISSING_NONCE,
NULL, &realm, &nonce, p_response);
@@ -319,24 +318,18 @@ PJ_DEF(pj_status_t) pj_stun_verify_credential( const pj_uint8_t *pkt,
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;
- }
+ /* Calculate key */
+ pj_stun_create_key(pool, &key, &realm, &auser->value, &password);
/* Now calculate HMAC of the message, adding zero padding if necessary
* to make the input 64 bytes aligned.
*/
pj_hmac_sha1_init(&ctx, (pj_uint8_t*)key.ptr, key.slen);
pj_hmac_sha1_update(&ctx, pkt, amsgi_pos);
- if (amsgi_pos & 0x3F) {
+ if (amsgi_pos & 63) {
pj_uint8_t zeroes[64];
pj_bzero(zeroes, sizeof(zeroes));
- pj_hmac_sha1_update(&ctx, zeroes, 64-(amsgi_pos & 0x3F));
+ pj_hmac_sha1_update(&ctx, zeroes, 64-(amsgi_pos & 63));
}
pj_hmac_sha1_final(&ctx, digest);
@@ -355,3 +348,77 @@ PJ_DEF(pj_status_t) pj_stun_verify_credential( const pj_uint8_t *pkt,
}
+/* Authenticate MESSAGE-INTEGRITY in the response */
+PJ_DEF(pj_status_t) pj_stun_authenticate_response(const pj_uint8_t *pkt,
+ unsigned pkt_len,
+ const pj_stun_msg *msg,
+ const pj_str_t *key)
+{
+ const pj_stun_msgint_attr *amsgi;
+ unsigned amsgi_pos;
+ pj_hmac_sha1_context ctx;
+ pj_uint8_t digest[PJ_SHA1_DIGEST_SIZE];
+
+ PJ_ASSERT_RETURN(pkt && pkt_len && msg && key, PJ_EINVAL);
+
+ /* 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) {
+ return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_INTEGRITY_CHECK_FAILURE);
+ }
+
+
+ /* Check that message length is valid */
+ if (msg->hdr.length < 24) {
+ return PJNATH_EINSTUNMSGLEN;
+ }
+
+ /* 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) {
+ /* Check that message length is valid */
+ if (msg->hdr.length < 32) {
+ return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_INTEGRITY_CHECK_FAILURE);
+ }
+
+ 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) {
+ return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_INTEGRITY_CHECK_FAILURE);
+ }
+
+ /* Now calculate HMAC of the message, adding zero padding if necessary
+ * to make the input 64 bytes aligned.
+ */
+ pj_hmac_sha1_init(&ctx, (pj_uint8_t*)key->ptr, key->slen);
+ pj_hmac_sha1_update(&ctx, pkt, amsgi_pos);
+ if (amsgi_pos & 0x3F) {
+ pj_uint8_t zeroes[64];
+ pj_bzero(zeroes, sizeof(zeroes));
+ pj_hmac_sha1_update(&ctx, zeroes, 64-(amsgi_pos & 0x3F));
+ }
+ pj_hmac_sha1_final(&ctx, digest);
+
+ /* Compare HMACs */
+ if (pj_memcmp(amsgi->hmac, digest, 20)) {
+ /* HMAC value mismatch */
+ return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_INTEGRITY_CHECK_FAILURE);
+ }
+
+ /* Everything looks okay! */
+ return PJ_SUCCESS;
+}
+
diff --git a/pjnath/src/pjnath/stun_msg.c b/pjnath/src/pjnath/stun_msg.c
index 0c17bc5b..74dbcfa9 100644
--- a/pjnath/src/pjnath/stun_msg.c
+++ b/pjnath/src/pjnath/stun_msg.c
@@ -17,7 +17,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pjnath/stun_msg.h>
-#include <pjnath/stun_auth.h>
#include <pjnath/errno.h>
#include <pjlib-util/crc32.h>
#include <pjlib-util/hmac_sha1.h>
@@ -1948,10 +1947,10 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
/* Calculate HMAC-SHA1 key for long term credential, by getting
* MD5 digest of username, realm, and password.
*/
-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)
+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)
{
/* The 16-byte key for MESSAGE-INTEGRITY HMAC is formed by taking
* the MD5 hash of the result of concatenating the following five
@@ -1966,9 +1965,9 @@ void pj_stun_calc_md5_key(pj_uint8_t digest[16],
pj_md5_init(&ctx);
#define REMOVE_QUOTE(s) if (s.slen && *s.ptr=='"') \
- s.ptr++, s.slen--; \
- if (s.slen && s.ptr[s.slen-1]=='"') \
- s.slen--;
+ s.ptr++, s.slen--; \
+ if (s.slen && s.ptr[s.slen-1]=='"') \
+ s.slen--;
/* Add username */
s = *username;
@@ -1997,6 +1996,28 @@ void pj_stun_calc_md5_key(pj_uint8_t digest[16],
/*
+ * Create authentication key to be used for encoding the message with
+ * MESSAGE-INTEGRITY.
+ */
+PJ_DEF(void) pj_stun_create_key(pj_pool_t *pool,
+ pj_str_t *key,
+ const pj_str_t *realm,
+ const pj_str_t *username,
+ const pj_str_t *passwd)
+{
+ PJ_ASSERT_ON_FAIL(pool && key && username && passwd, return);
+
+ if (realm && realm->slen) {
+ key->ptr = (char*) pj_pool_alloc(pool, 16);
+ calc_md5_key((pj_uint8_t*)key->ptr, realm, username, passwd);
+ key->slen = 16;
+ } else {
+ pj_strdup(pool, key, passwd);
+ }
+}
+
+
+/*
static char *print_binary(const pj_uint8_t *data, unsigned data_len)
{
static char static_buffer[1024];
@@ -2028,16 +2049,13 @@ static char *print_binary(const pj_uint8_t *data, unsigned data_len)
PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
pj_uint8_t *buf, unsigned buf_size,
unsigned options,
- const pj_str_t *password,
+ const pj_str_t *key,
unsigned *p_msg_len)
{
- pj_stun_msg_hdr *hdr;
pj_uint8_t *start = buf;
- pj_stun_realm_attr *arealm = NULL;
- pj_stun_username_attr *auname = NULL;
pj_stun_msgint_attr *amsgint = NULL;
pj_stun_fingerprint_attr *afingerprint = NULL;
- unsigned printed = 0;
+ unsigned printed = 0, body_len;
pj_status_t status;
unsigned i;
@@ -2052,16 +2070,16 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
*/
if (buf_size < sizeof(pj_stun_msg_hdr))
return PJ_ETOOSMALL;
- pj_memcpy(buf, &msg->hdr, sizeof(pj_stun_msg_hdr));
- hdr = (pj_stun_msg_hdr*) buf;
- hdr->magic = pj_htonl(hdr->magic);
- hdr->type = pj_htons(hdr->type);
- /* We'll fill in the length later */
+
+ PUTVAL16H(buf, 0, msg->hdr.type);
+ PUTVAL16H(buf, 2, 0); /* length will be calculated later */
+ PUTVAL32H(buf, 4, msg->hdr.magic);
+ pj_memcpy(buf+8, msg->hdr.tsx_id, sizeof(msg->hdr.tsx_id));
buf += sizeof(pj_stun_msg_hdr);
buf_size -= sizeof(pj_stun_msg_hdr);
- /* Print each attribute */
+ /* Encode each attribute to the message */
for (i=0; i<msg->attr_count; ++i) {
const struct attr_desc *adesc;
const pj_stun_attr_hdr *attr_hdr = msg->attr[i];
@@ -2073,14 +2091,6 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
/* Stop when encountering MESSAGE-INTEGRITY */
break;
- } else if (attr_hdr->type == PJ_STUN_ATTR_USERNAME) {
- pj_assert(auname == NULL);
- auname = (pj_stun_username_attr*) attr_hdr;
-
- } else if (attr_hdr->type == PJ_STUN_ATTR_REALM) {
- pj_assert(arealm == NULL);
- arealm = (pj_stun_realm_attr*) attr_hdr;
-
} else if (attr_hdr->type == PJ_STUN_ATTR_FINGERPRINT) {
afingerprint = (pj_stun_fingerprint_attr*) attr_hdr;
break;
@@ -2123,25 +2133,24 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
* Note that length is not including the 20 bytes header.
*/
if (amsgint && afingerprint) {
- msg->hdr.length = (pj_uint16_t)((buf - start) - 20 + 24 + 8);
+ body_len = (pj_uint16_t)((buf - start) - 20 + 24 + 8);
} else if (amsgint) {
- msg->hdr.length = (pj_uint16_t)((buf - start) - 20 + 24);
+ body_len = (pj_uint16_t)((buf - start) - 20 + 24);
} else if (afingerprint) {
- msg->hdr.length = (pj_uint16_t)((buf - start) - 20 + 8);
+ body_len = (pj_uint16_t)((buf - start) - 20 + 8);
} else {
- msg->hdr.length = (pj_uint16_t)((buf - start) - 20);
+ body_len = (pj_uint16_t)((buf - start) - 20);
}
/* hdr->length = pj_htons(length); */
- start[2] = (pj_uint8_t)((msg->hdr.length >> 8) & 0x00FF);
- start[3] = (pj_uint8_t)(msg->hdr.length & 0x00FF);
+ PUTVAL16H(start, 2, (pj_uint16_t)body_len);
/* Calculate message integrity, if present */
if (amsgint != NULL) {
-
- pj_uint8_t md5_key_buf[16];
pj_hmac_sha1_context ctx;
- pj_str_t key;
+
+ /* Key MUST be specified */
+ PJ_ASSERT_RETURN(key, PJ_EINVALIDOP);
/* MESSAGE-INTEGRITY must be the last attribute in the message, or
* the last attribute before FINGERPRINT.
@@ -2161,32 +2170,10 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
}
}
- /* Must have USERNAME attribute */
- if (auname == NULL) {
- /* Should not happen for message generated by us */
- pj_assert(PJ_FALSE);
- return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_MISSING_USERNAME);
- }
-
- /* Password must be specified */
- PJ_ASSERT_RETURN(password, PJ_EINVAL);
-
- /* Get the key to sign the message */
- if (arealm == NULL ) {
- /* For short term credential, the key is the password */
- key = *password;
-
- } else {
- pj_stun_calc_md5_key(md5_key_buf, &arealm->value,
- &auname->value, password);
- key.ptr = (char*) md5_key_buf;
- key.slen = 16;
- }
-
/* Calculate HMAC-SHA1 digest, add zero padding to input
* if necessary to make the input 64 bytes aligned.
*/
- pj_hmac_sha1_init(&ctx, (pj_uint8_t*)key.ptr, key.slen);
+ pj_hmac_sha1_init(&ctx, (pj_uint8_t*)key->ptr, key->slen);
pj_hmac_sha1_update(&ctx, (pj_uint8_t*)start, buf-start);
if ((buf-start) & 0x3F) {
pj_uint8_t zeroes[64];
@@ -2220,7 +2207,10 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
buf_size -= printed;
}
- /* Done */
+ /* Update message length. */
+ msg->hdr.length = (pj_uint16_t) ((buf - start) - 20);
+
+ /* Return the length */
if (p_msg_len)
*p_msg_len = (buf - start);
diff --git a/pjnath/src/pjnath/stun_session.c b/pjnath/src/pjnath/stun_session.c
index 541288de..7586dfc2 100644
--- a/pjnath/src/pjnath/stun_session.c
+++ b/pjnath/src/pjnath/stun_session.c
@@ -211,13 +211,18 @@ static void on_cache_timeout(pj_timer_heap_t *timer_heap,
pj_stun_msg_destroy_tdata(tdata->sess, tdata);
}
-static pj_str_t *get_passwd(pj_stun_session *sess, pj_pool_t *pool,
- const pj_stun_msg *msg)
+static pj_status_t get_key(pj_stun_session *sess, pj_pool_t *pool,
+ const pj_stun_msg *msg, pj_str_t *auth_key)
{
if (sess->cred == NULL) {
- return NULL;
+ auth_key->slen = 0;
+ return PJ_SUCCESS;
} else if (sess->cred->type == PJ_STUN_AUTH_CRED_STATIC) {
- return &sess->cred->data.static_cred.data;
+ pj_stun_create_key(pool, auth_key,
+ &sess->cred->data.static_cred.realm,
+ &sess->cred->data.static_cred.username,
+ &sess->cred->data.static_cred.data);
+ return PJ_SUCCESS;
} else if (sess->cred->type == PJ_STUN_AUTH_CRED_DYNAMIC) {
pj_str_t realm, username, nonce;
pj_str_t *password;
@@ -231,10 +236,17 @@ static pj_str_t *get_passwd(pj_stun_session *sess, pj_pool_t *pool,
&realm, &username,
&nonce, &data_type,
password);
- return password;
+ if (status != PJ_SUCCESS)
+ return status;
+
+ pj_stun_create_key(pool, auth_key,
+ &realm, &username, password);
+
+ return PJ_SUCCESS;
} else {
- return NULL;
+ pj_assert(!"Unknown credential type");
+ return PJ_EBUG;
}
}
@@ -243,26 +255,23 @@ static pj_status_t apply_msg_options(pj_stun_session *sess,
pj_stun_msg *msg)
{
pj_status_t status = 0;
+ pj_bool_t need_auth;
pj_str_t realm, username, nonce, password;
int data_type = 0;
realm.slen = username.slen = nonce.slen = password.slen = 0;
/* The server SHOULD include a SERVER attribute in all responses */
- if (sess->srv_name.slen && (PJ_STUN_IS_SUCCESS_RESPONSE(msg->hdr.type) ||
- PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)))
- {
+ if (sess->srv_name.slen && PJ_STUN_IS_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.
- */
+ need_auth = PJ_STUN_IS_REQUEST(msg->hdr.type) ||
+ PJ_STUN_IS_SUCCESS_RESPONSE(msg->hdr.type);
+
if (sess->cred && sess->cred->type == PJ_STUN_AUTH_CRED_STATIC &&
- !PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))
+ need_auth)
{
realm = sess->cred->data.static_cred.realm;
username = sess->cred->data.static_cred.username;
@@ -271,7 +280,7 @@ static pj_status_t apply_msg_options(pj_stun_session *sess,
nonce = sess->cred->data.static_cred.nonce;
} else if (sess->cred && sess->cred->type == PJ_STUN_AUTH_CRED_DYNAMIC &&
- !PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))
+ need_auth)
{
void *user_data = sess->cred->data.dyn_cred.user_data;
@@ -284,8 +293,8 @@ static pj_status_t apply_msg_options(pj_stun_session *sess,
}
- /* Create and add USERNAME attribute */
- if (username.slen) {
+ /* Create and add USERNAME attribute for */
+ if (username.slen && PJ_STUN_IS_REQUEST(msg->hdr.type)) {
status = pj_stun_msg_add_string_attr(pool, msg,
PJ_STUN_ATTR_USERNAME,
&username);
@@ -293,7 +302,7 @@ static pj_status_t apply_msg_options(pj_stun_session *sess,
}
/* Add REALM only when long term credential is used */
- if (realm.slen) {
+ if (realm.slen && PJ_STUN_IS_REQUEST(msg->hdr.type)) {
status = pj_stun_msg_add_string_attr(pool, msg,
PJ_STUN_ATTR_REALM,
&realm);
@@ -301,14 +310,17 @@ static pj_status_t apply_msg_options(pj_stun_session *sess,
}
/* Add NONCE when desired */
- if (nonce.slen) {
+ if (nonce.slen &&
+ (PJ_STUN_IS_REQUEST(msg->hdr.type) ||
+ PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)))
+ {
status = pj_stun_msg_add_string_attr(pool, msg,
PJ_STUN_ATTR_NONCE,
&nonce);
}
/* Add MESSAGE-INTEGRITY attribute */
- if (username.slen) {
+ if (username.slen && need_auth) {
status = pj_stun_msg_add_msgint_attr(pool, msg);
PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
}
@@ -508,11 +520,11 @@ PJ_DEF(pj_status_t) pj_stun_session_create_ind(pj_stun_session *sess,
/*
* Create a STUN response message.
*/
-PJ_DEF(pj_status_t) pj_stun_session_create_response( pj_stun_session *sess,
- const pj_stun_msg *req,
- unsigned err_code,
- const pj_str_t *err_msg,
- pj_stun_tx_data **p_tdata)
+PJ_DEF(pj_status_t) pj_stun_session_create_res( pj_stun_session *sess,
+ const pj_stun_msg *req,
+ unsigned err_code,
+ const pj_str_t *err_msg,
+ pj_stun_tx_data **p_tdata)
{
pj_status_t status;
pj_stun_tx_data *tdata = NULL;
@@ -597,10 +609,18 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
return status;
}
+ status = get_key(sess, tdata->pool, tdata->msg, &tdata->auth_key);
+ if (status != PJ_SUCCESS) {
+ pj_stun_msg_destroy_tdata(sess, tdata);
+ pj_mutex_unlock(sess->mutex);
+ LOG_ERR_(sess, "Error getting creadential's key", status);
+ return status;
+ }
+
/* Encode message */
status = pj_stun_msg_encode(tdata->msg, (pj_uint8_t*)tdata->pkt,
tdata->max_len, 0,
- get_passwd(sess, tdata->pool, tdata->msg),
+ &tdata->auth_key,
&tdata->pkt_size);
if (status != PJ_SUCCESS) {
pj_stun_msg_destroy_tdata(sess, tdata);
@@ -737,6 +757,7 @@ PJ_DEF(pj_status_t) pj_stun_session_retransmit_req(pj_stun_session *sess,
/* Send response */
static pj_status_t send_response(pj_stun_session *sess,
pj_pool_t *pool, pj_stun_msg *response,
+ const pj_str_t *auth_key,
pj_bool_t retransmission,
const pj_sockaddr_t *addr, unsigned addr_len)
{
@@ -757,8 +778,7 @@ static pj_status_t send_response(pj_stun_session *sess,
/* Encode */
status = pj_stun_msg_encode(response, out_pkt, out_max_len, 0,
- get_passwd(sess, pool, response),
- &out_len);
+ auth_key, &out_len);
if (status != PJ_SUCCESS) {
LOG_ERR_(sess, "Error encoding message", status);
return status;
@@ -774,7 +794,7 @@ static pj_status_t send_response(pj_stun_session *sess,
}
/* Authenticate incoming message */
-static pj_status_t authenticate_msg(pj_stun_session *sess,
+static pj_status_t authenticate_req(pj_stun_session *sess,
const pj_uint8_t *pkt,
unsigned pkt_len,
const pj_stun_msg *msg,
@@ -788,11 +808,11 @@ static pj_status_t authenticate_msg(pj_stun_session *sess,
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);
+ status = pj_stun_authenticate_request(pkt, pkt_len, msg, sess->cred,
+ tmp_pool, &response);
if (status != PJ_SUCCESS && response != NULL) {
PJ_LOG(5,(SNAME(sess), "Message authentication failed"));
- send_response(sess, tmp_pool, response, PJ_FALSE,
+ send_response(sess, tmp_pool, response, NULL, PJ_FALSE,
src_addr, src_addr_len);
}
@@ -802,6 +822,9 @@ static pj_status_t authenticate_msg(pj_stun_session *sess,
/* Handle incoming response */
static pj_status_t on_incoming_response(pj_stun_session *sess,
+ unsigned options,
+ const pj_uint8_t *pkt,
+ unsigned pkt_len,
pj_stun_msg *msg,
const pj_sockaddr_t *src_addr,
unsigned src_addr_len)
@@ -817,6 +840,18 @@ static pj_status_t on_incoming_response(pj_stun_session *sess,
return PJ_SUCCESS;
}
+ /* Authenticate the message, unless PJ_STUN_NO_AUTHENTICATE
+ * is specified in the option.
+ */
+ if ((options & PJ_STUN_NO_AUTHENTICATE) == 0) {
+ status = pj_stun_authenticate_response(pkt, pkt_len, msg, &tdata->auth_key);
+ if (status != PJ_SUCCESS) {
+ PJ_LOG(5,(SNAME(sess),
+ "Response authentication failed"));
+ return status;
+ }
+ }
+
/* Pass the response to the transaction.
* If the message is accepted, transaction callback will be called,
* and this will call the session callback too.
@@ -866,7 +901,7 @@ static pj_status_t check_cached_response(pj_stun_session *sess,
PJ_LOG(5,(SNAME(sess),
"Request retransmission, sending cached response"));
- send_response(sess, tmp_pool, t->msg, PJ_TRUE,
+ send_response(sess, tmp_pool, t->msg, &t->auth_key, PJ_TRUE,
src_addr, src_addr_len);
return PJ_SUCCESS;
}
@@ -876,6 +911,7 @@ static pj_status_t check_cached_response(pj_stun_session *sess,
/* Handle incoming request */
static pj_status_t on_incoming_request(pj_stun_session *sess,
+ unsigned options,
pj_pool_t *tmp_pool,
const pj_uint8_t *in_pkt,
unsigned in_pkt_len,
@@ -885,6 +921,17 @@ static pj_status_t on_incoming_request(pj_stun_session *sess,
{
pj_status_t status;
+ /* Authenticate the message, unless PJ_STUN_NO_AUTHENTICATE
+ * is specified in the option.
+ */
+ if ((options & PJ_STUN_NO_AUTHENTICATE) == 0) {
+ status = authenticate_req(sess, (const pj_uint8_t*) in_pkt, in_pkt_len,
+ msg, tmp_pool, src_addr, src_addr_len);
+ if (status != PJ_SUCCESS) {
+ return status;
+ }
+ }
+
/* Distribute to handler, or respond with Bad Request */
if (sess->cb.on_rx_request) {
status = (*sess->cb.on_rx_request)(sess, in_pkt, in_pkt_len, msg,
@@ -897,7 +944,7 @@ static pj_status_t on_incoming_request(pj_stun_session *sess,
&response);
if (status == PJ_SUCCESS && response) {
status = send_response(sess, tmp_pool, response,
- PJ_FALSE, src_addr, src_addr_len);
+ NULL, PJ_FALSE, src_addr, src_addr_len);
}
}
@@ -952,7 +999,7 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
if (status != PJ_SUCCESS) {
LOG_ERR_(sess, "STUN msg_decode() error", status);
if (response) {
- send_response(sess, tmp_pool, response,
+ send_response(sess, tmp_pool, response, NULL,
PJ_FALSE, src_addr, src_addr_len);
}
pj_pool_release(tmp_pool);
@@ -977,26 +1024,17 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
goto on_return;
}
- /* Authenticate the message, unless PJ_STUN_NO_AUTHENTICATE
- * is specified in the option.
- */
- if ((options & PJ_STUN_NO_AUTHENTICATE) == 0) {
- status = authenticate_msg(sess, (const pj_uint8_t*) packet, pkt_size,
- msg, tmp_pool, src_addr, src_addr_len);
- if (status != PJ_SUCCESS) {
- goto on_return;
- }
- }
-
/* Handle message */
if (PJ_STUN_IS_SUCCESS_RESPONSE(msg->hdr.type) ||
PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))
{
- status = on_incoming_response(sess, msg, src_addr, src_addr_len);
+ status = on_incoming_response(sess, options,
+ (const pj_uint8_t*) packet, pkt_size,
+ msg, src_addr, src_addr_len);
} else if (PJ_STUN_IS_REQUEST(msg->hdr.type)) {
- status = on_incoming_request(sess, tmp_pool,
+ status = on_incoming_request(sess, options, tmp_pool,
(const pj_uint8_t*) packet, pkt_size,
msg, src_addr, src_addr_len);
diff --git a/pjnath/src/pjnath/stun_transaction.c b/pjnath/src/pjnath/stun_transaction.c
index 30330718..88b19c95 100644
--- a/pjnath/src/pjnath/stun_transaction.c
+++ b/pjnath/src/pjnath/stun_transaction.c
@@ -188,11 +188,11 @@ static pj_status_t tsx_transmit_msg(pj_stun_client_tsx *tsx)
tsx->retransmit_time.sec = 0;
tsx->retransmit_time.msec = tsx->cfg->rto_msec;
- } else if (tsx->transmit_count < PJ_STUN_MAX_RETRANSMIT_COUNT-1) {
+ } else if (tsx->transmit_count < PJ_STUN_MAX_TRANSMIT_COUNT-1) {
unsigned msec;
msec = PJ_TIME_VAL_MSEC(tsx->retransmit_time);
- msec = (msec << 1) + 100;
+ msec <<= 1;
tsx->retransmit_time.sec = msec / 1000;
tsx->retransmit_time.msec = msec % 1000;
@@ -216,6 +216,11 @@ static pj_status_t tsx_transmit_msg(pj_stun_client_tsx *tsx)
}
+ tsx->transmit_count++;
+
+ PJ_LOG(5,(tsx->obj_name, "STUN sending message (transmit count=%d)",
+ tsx->transmit_count));
+
/* Send message */
status = tsx->cb.on_send_msg(tsx, tsx->last_pkt, tsx->last_pkt_size);
if (status != PJ_SUCCESS) {
@@ -228,10 +233,6 @@ static pj_status_t tsx_transmit_msg(pj_stun_client_tsx *tsx)
return status;
}
- tsx->transmit_count++;
-
- PJ_LOG(5,(tsx->obj_name, "STUN sending message (transmit count=%d)",
- tsx->transmit_count));
return status;
}
@@ -268,7 +269,7 @@ static void retransmit_timer_callback(pj_timer_heap_t *timer_heap,
PJ_UNUSED_ARG(timer_heap);
- if (tsx->transmit_count >= PJ_STUN_MAX_RETRANSMIT_COUNT) {
+ if (tsx->transmit_count >= PJ_STUN_MAX_TRANSMIT_COUNT) {
/* Retransmission count exceeded. Transaction has failed */
tsx->retransmit_timer.id = 0;
PJ_LOG(4,(tsx->obj_name, "STUN timeout waiting for response"));
diff --git a/pjnath/src/pjstun-client/client_main.c b/pjnath/src/pjstun-client/client_main.c
index 10834105..567a6b75 100644
--- a/pjnath/src/pjstun-client/client_main.c
+++ b/pjnath/src/pjstun-client/client_main.c
@@ -107,6 +107,15 @@ static void on_request_complete(pj_stun_session *sess,
case PJ_STUN_ALLOCATE_RESPONSE:
{
pj_stun_relay_addr_attr *ar;
+ pj_stun_lifetime_attr *al;
+
+ al = (pj_stun_lifetime_attr*)
+ pj_stun_msg_find_attr(response,
+ PJ_STUN_ATTR_LIFETIME, 0);
+ if (!al) {
+ PJ_LOG(1,(THIS_FILE, "Error: LIFETIME attribute not present"));
+ return;
+ }
ar = (pj_stun_relay_addr_attr*)
pj_stun_msg_find_attr(response,
@@ -120,6 +129,10 @@ static void on_request_complete(pj_stun_session *sess,
} else {
pj_memset(&g.relay_addr, 0, sizeof(g.relay_addr));
}
+
+ if (al->value == 0) {
+ PJ_LOG(3,(THIS_FILE, "Relay deallocated"));
+ }
}
break;
}
@@ -632,7 +645,7 @@ int main(int argc, char *argv[])
g.data = g.data_buf;
- while((c=pj_getopt_long(argc,argv, "r:u:p:hF", long_options, &opt_id))!=-1) {
+ while((c=pj_getopt_long(argc,argv, "r:u:p:N:hF", long_options, &opt_id))!=-1) {
switch (c) {
case 'r':
o.realm = pj_optarg;
diff --git a/pjnath/src/pjstun-srv-test/bind_usage.c b/pjnath/src/pjstun-srv-test/bind_usage.c
index 680dd5c0..09112bdd 100644
--- a/pjnath/src/pjstun-srv-test/bind_usage.c
+++ b/pjnath/src/pjstun-srv-test/bind_usage.c
@@ -157,7 +157,7 @@ static pj_status_t sess_on_rx_request(pj_stun_session *sess,
PJ_UNUSED_ARG(pkt_len);
/* Create response */
- status = pj_stun_session_create_response(sess, msg, 0, NULL, &tdata);
+ status = pj_stun_session_create_res(sess, msg, 0, NULL, &tdata);
if (status != PJ_SUCCESS)
return status;
diff --git a/pjnath/src/pjstun-srv-test/main.c b/pjnath/src/pjstun-srv-test/main.c
index c462d47e..aad1c0f2 100644
--- a/pjnath/src/pjstun-srv-test/main.c
+++ b/pjnath/src/pjstun-srv-test/main.c
@@ -78,9 +78,10 @@ int main(int argc, char *argv[])
int c, opt_id;
pj_caching_pool cp;
pj_stun_server *srv;
+ pj_stun_usage *turn;
pj_status_t status;
- while((c=pj_getopt_long(argc,argv, "r:u:p:hF", long_options, &opt_id))!=-1) {
+ while((c=pj_getopt_long(argc,argv, "r:u:p:N:hF", long_options, &opt_id))!=-1) {
switch (c) {
case 'r':
o.realm = pj_optarg;
@@ -131,12 +132,24 @@ int main(int argc, char *argv[])
*/
status = pj_stun_turn_usage_create(srv, PJ_SOCK_DGRAM, NULL,
- 3478, NULL);
+ 3478, &turn);
if (status != PJ_SUCCESS) {
pj_stun_perror(THIS_FILE, "Unable to create bind usage", status);
return 1;
}
+ if (o.user_name && o.password) {
+ 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_turn_usage_set_credential(turn, &cred);
+ }
+
server_main(srv);
pj_stun_server_destroy(srv);
diff --git a/pjnath/src/pjstun-srv-test/server.h b/pjnath/src/pjstun-srv-test/server.h
index 633131c6..f06d7f85 100644
--- a/pjnath/src/pjstun-srv-test/server.h
+++ b/pjnath/src/pjstun-srv-test/server.h
@@ -124,6 +124,8 @@ PJ_DECL(pj_status_t) pj_stun_turn_usage_create(pj_stun_server *srv,
unsigned port,
pj_stun_usage **p_bu);
+PJ_DECL(pj_status_t) pj_stun_turn_usage_set_credential(pj_stun_usage *turn,
+ const pj_stun_auth_cred *cred);
pj_status_t pj_stun_server_register_usage(pj_stun_server *srv,
pj_stun_usage *usage);
diff --git a/pjnath/src/pjstun-srv-test/turn_usage.c b/pjnath/src/pjstun-srv-test/turn_usage.c
index 145d8020..c3e53577 100644
--- a/pjnath/src/pjstun-srv-test/turn_usage.c
+++ b/pjnath/src/pjstun-srv-test/turn_usage.c
@@ -78,6 +78,7 @@ struct turn_usage
int type;
pj_stun_session *default_session;
pj_hash_table_t *client_htable;
+ pj_stun_auth_cred *cred;
unsigned max_bw_kbps;
unsigned max_lifetime;
@@ -225,6 +226,19 @@ PJ_DEF(pj_status_t) pj_stun_turn_usage_create(pj_stun_server *srv,
}
+PJ_DEF(pj_status_t) pj_stun_turn_usage_set_credential(pj_stun_usage *turn,
+ const pj_stun_auth_cred *c)
+{
+ struct turn_usage *tu;
+ tu = (struct turn_usage*) pj_stun_usage_get_user_data(turn);
+
+ tu->cred = PJ_POOL_ZALLOC_T(tu->pool, pj_stun_auth_cred);
+ pj_stun_auth_cred_dup(tu->pool, tu->cred, c);
+ pj_stun_session_set_credential(tu->default_session, tu->cred);
+ return PJ_SUCCESS;
+}
+
+
/*
* This is a callback called by usage.c when the particular STUN usage
* is to be destroyed.
@@ -441,9 +455,9 @@ static pj_status_t tu_sess_on_rx_request(pj_stun_session *sess,
} else if (msg->hdr.type != PJ_STUN_ALLOCATE_REQUEST) {
if (PJ_STUN_IS_REQUEST(msg->hdr.type)) {
- status = pj_stun_session_create_response(sess, msg,
- PJ_STUN_SC_NO_BINDING,
- NULL, &tdata);
+ status = pj_stun_session_create_res(sess, msg,
+ PJ_STUN_SC_NO_BINDING,
+ NULL, &tdata);
if (status==PJ_SUCCESS) {
status = pj_stun_session_send_msg(sess, PJ_FALSE,
src_addr, src_addr_len,
@@ -630,6 +644,9 @@ static pj_status_t client_create(struct turn_usage *tu,
return status;
}
+ if (tu->cred)
+ pj_stun_session_set_credential(client->session, tu->cred);
+
sd = PJ_POOL_ZALLOC_T(pool, struct session_data);
sd->tu = tu;
sd->client = client;
@@ -863,9 +880,9 @@ static pj_status_t client_respond(struct turn_client *client,
if (custom_msg)
pj_cstr(&err_msg, custom_msg), p_err_msg = &err_msg;
- status = pj_stun_session_create_response(client->session, msg,
- err_code, p_err_msg,
- &response);
+ status = pj_stun_session_create_res(client->session, msg,
+ err_code, p_err_msg,
+ &response);
if (status == PJ_SUCCESS)
status = pj_stun_session_send_msg(client->session, PJ_TRUE,
dst_addr, dst_addr_len, response);
@@ -1014,8 +1031,8 @@ static pj_status_t client_handle_allocate_req(struct turn_client *client,
client->expiry_timer.id = PJ_TRUE;
/* Done successfully, create and send success response */
- status = pj_stun_session_create_response(client->session, msg,
- 0, NULL, &response);
+ status = pj_stun_session_create_res(client->session, msg,
+ 0, NULL, &response);
if (status != PJ_SUCCESS) {
return status;
}
@@ -1062,8 +1079,8 @@ static pj_status_t handle_binding_req(pj_stun_session *session,
pj_status_t status;
/* Create response */
- status = pj_stun_session_create_response(session, msg, 0, NULL,
- &tdata);
+ status = pj_stun_session_create_res(session, msg, 0, NULL,
+ &tdata);
if (status != PJ_SUCCESS)
return status;
diff --git a/third_party/build/Makefile b/third_party/build/Makefile
index 204adcf5..82ca9855 100644
--- a/third_party/build/Makefile
+++ b/third_party/build/Makefile
@@ -1,3 +1,5 @@
+DIRS = resample
+
include ../../build.mak
include $(PJDIR)/build/common.mak
diff --git a/third_party/build/os-auto.mak.in b/third_party/build/os-auto.mak.in
index 82c90e3b..94db5ac2 100644
--- a/third_party/build/os-auto.mak.in
+++ b/third_party/build/os-auto.mak.in
@@ -1,4 +1,3 @@
-DIRS = resample
ifneq (@ac_no_gsm_codec@,1)
DIRS += gsm