summaryrefslogtreecommitdiff
path: root/pjnath
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-03-29 21:54:21 +0000
committerBenny Prijono <bennylp@teluu.com>2007-03-29 21:54:21 +0000
commit3bde23647e94fe0764c8e32d53537e6b116e71de (patch)
tree7c8aa98ecff5193e7b89e6f44697b9f7538d59b3 /pjnath
parent7d29fabefb6405ea7bc47b8d9a465df5af96612c (diff)
Added ICE-CONTROLLING and ICE-CONTROLLED STUN attribute types
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1114 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjnath')
-rw-r--r--pjnath/include/pjnath/ice_session.h16
-rw-r--r--pjnath/include/pjnath/ice_strans.h3
-rw-r--r--pjnath/include/pjnath/stun_msg.h71
-rw-r--r--pjnath/include/pjnath/types.h45
-rw-r--r--pjnath/src/pjnath/ice_session.c29
-rw-r--r--pjnath/src/pjnath/ice_strans.c106
-rw-r--r--pjnath/src/pjnath/stun_msg.c419
-rw-r--r--pjnath/src/pjnath/stun_msg_dump.c2
-rw-r--r--pjnath/src/pjnath/stun_transaction.c7
9 files changed, 451 insertions, 247 deletions
diff --git a/pjnath/include/pjnath/ice_session.h b/pjnath/include/pjnath/ice_session.h
index fd7da751..929a4e82 100644
--- a/pjnath/include/pjnath/ice_session.h
+++ b/pjnath/include/pjnath/ice_session.h
@@ -444,6 +444,7 @@ struct pj_ice_sess
void *user_data; /**< App. data. */
pj_mutex_t *mutex; /**< Mutex. */
pj_ice_sess_role role; /**< ICE role. */
+ pj_timestamp tie_breaker; /**< Tie breaker value */
pj_bool_t is_complete; /**< Complete? */
pj_status_t ice_status; /**< Error status. */
pj_ice_sess_cb cb; /**< Callback. */
@@ -550,6 +551,21 @@ PJ_DECL(pj_status_t) pj_ice_sess_destroy(pj_ice_sess *ice);
/**
+ * Change session role. This happens for example when ICE session was
+ * created with controlled role when receiving an offer, but it turns out
+ * that the offer contains "a=ice-lite" attribute when the SDP gets
+ * inspected.
+ *
+ * @param ice The ICE session.
+ * @param new_role The new role to be set.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error.
+ */
+PJ_DECL(pj_status_t) pj_ice_sess_change_role(pj_ice_sess *ice,
+ pj_ice_sess_role new_role);
+
+
+/**
* Add a candidate to this ICE session. Application must add candidates for
* each components ID before it can start pairing the candidates and
* performing connectivity checks.
diff --git a/pjnath/include/pjnath/ice_strans.h b/pjnath/include/pjnath/ice_strans.h
index b26b6a49..59243a00 100644
--- a/pjnath/include/pjnath/ice_strans.h
+++ b/pjnath/include/pjnath/ice_strans.h
@@ -27,6 +27,7 @@
#include <pjnath/ice_session.h>
#include <pjlib-util/resolver.h>
#include <pj/ioqueue.h>
+#include <pj/timer.h>
PJ_BEGIN_DECL
@@ -314,6 +315,8 @@ struct pj_ice_strans
pj_bool_t has_rjob; /**< Has pending resolve? */
pj_sockaddr_in stun_srv; /**< STUN server address. */
pj_sockaddr_in turn_srv; /**< TURN server address. */
+
+ pj_timer_entry ka_timer; /**< STUN keep-alive timer. */
};
diff --git a/pjnath/include/pjnath/stun_msg.h b/pjnath/include/pjnath/stun_msg.h
index 6c43ee9b..6c716a0c 100644
--- a/pjnath/include/pjnath/stun_msg.h
+++ b/pjnath/include/pjnath/stun_msg.h
@@ -310,6 +310,8 @@ typedef enum pj_stun_attr_type
PJ_STUN_ATTR_ALTERNATE_SERVER = 0x8023,/**< ALTERNATE-SERVER. */
PJ_STUN_ATTR_REFRESH_INTERVAL = 0x8024,/**< REFRESH-INTERVAL. */
PJ_STUN_ATTR_FINGERPRINT = 0x8028,/**< FINGERPRINT attribute. */
+ PJ_STUN_ATTR_ICE_CONTROLLED = 0x8029,/**< ICE-CCONTROLLED attribute.*/
+ PJ_STUN_ATTR_ICE_CONTROLLING = 0x802a,/**< ICE-CCONTROLLING attribute*/
PJ_STUN_ATTR_END_EXTENDED_ATTR
@@ -344,6 +346,7 @@ typedef enum pj_stun_status
PJ_STUN_SC_CONNECTION_TIMEOUT = 447, /**< Connection Timeout */
PJ_STUN_SC_ALLOCATION_QUOTA_REACHED = 486, /**< Allocation Quota Reached
(TURN) */
+ PJ_STUN_SC_ROLE_CONFLICT = 487, /**< Role Conflict */
PJ_STUN_SC_SERVER_ERROR = 500, /**< Server Error */
PJ_STUN_SC_INSUFFICIENT_CAPACITY = 507, /**< Insufficient Capacity
(TURN) */
@@ -418,8 +421,6 @@ typedef struct pj_stun_msg_hdr
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Value .... |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
\endverbatim
*/
@@ -533,7 +534,7 @@ typedef struct pj_stun_uint_attr
pj_stun_attr_hdr hdr;
/**
- * The 32bit value.
+ * The 32bit value, in host byte order.
*/
pj_uint32_t value;
@@ -541,6 +542,25 @@ typedef struct pj_stun_uint_attr
/**
+ * This structure represents a generic STUN attributes with 64bit (unsigned)
+ * integer value, such as ICE-CONTROLLED and ICE-CONTROLLING attributes.
+ */
+typedef struct pj_stun_uint64_attr
+{
+ /**
+ * Standard STUN attribute header.
+ */
+ pj_stun_attr_hdr hdr;
+
+ /**
+ * The 64bit value, in host byte order, represented with pj_timestamp.
+ */
+ pj_timestamp value;
+
+} pj_stun_uint64_attr;
+
+
+/**
* This structure represents generic STUN attributes to hold a raw binary
* data.
*/
@@ -621,19 +641,9 @@ typedef struct pj_stun_errcode_attr
pj_stun_attr_hdr hdr;
/**
- * The value must be zero.
- */
- pj_uint16_t zero;
-
- /**
- * Error class (1-6).
- */
- pj_uint8_t err_class;
-
- /**
- * Error number is the error number modulo 100.
+ * STUN error code.
*/
- pj_uint8_t number;
+ int err_code;
/**
* The reason phrase.
@@ -1349,6 +1359,37 @@ PJ_DECL(pj_status_t) pj_stun_msg_add_uint_attr(pj_pool_t *pool,
/**
+ * Create a STUN generic 64bit value attribute.
+ *
+ * @param pool Pool to allocate memory from.
+ * @param attr_type Attribute type, from #pj_stun_attr_type.
+ * @param value Optional value to be assigned.
+ * @param p_attr Pointer to receive the attribute.
+ *
+ * @return PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DEF(pj_status_t) pj_stun_uint64_attr_create(pj_pool_t *pool,
+ int attr_type,
+ const pj_timestamp *value,
+ pj_stun_uint64_attr **p_attr);
+
+
+/**
+ * Create and add STUN generic 64bit value attribute to the message.
+ *
+ * @param pool The pool to allocate memory from.
+ * @param msg The STUN message
+ * @param attr_type Attribute type, from #pj_stun_attr_type.
+ * @param value The 64bit value to be assigned to the attribute.
+ *
+ * @return PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_stun_msg_add_uint64_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int attr_type,
+ const pj_timestamp *value);
+
+/**
* Create a STUN MESSAGE-INTEGRITY attribute.
*
* @param pool The pool to allocate memory from.
diff --git a/pjnath/include/pjnath/types.h b/pjnath/include/pjnath/types.h
index 2eaf6313..72c326af 100644
--- a/pjnath/include/pjnath/types.h
+++ b/pjnath/include/pjnath/types.h
@@ -51,18 +51,11 @@ PJ_END_DECL
/* Doxygen documentation below: */
/**
- * @mainpage PJNATH - Open Source STUN, TURN, and ICE Library
+ * @mainpage PJNATH - Open Source ICE, STUN, and TURN Library
*
* \n
* This is the documentation of PJNATH, an Open Source library providing
- * NAT traversal helper functionalities by using standard based protocols
- * such as:
- * - <b>STUN</b> (Session Traversal Utilities),
- * - <b>TURN</b> (Obtaining Relay Addresses from STUN)
- * - <b>ICE</b> (Interactive Connectivity Establishment).
- *
- * The following sections will give a short overview about the protocols
- * supported by this library, and how they are implemented in PJNATH.
+ * NAT traversal helper functionalities by using standard based protocols.
*
* \n
@@ -70,15 +63,10 @@ PJ_END_DECL
*
* Session Traversal Utilities (STUN, or previously known as Simple
* Traversal of User Datagram Protocol (UDP) Through Network Address
- * Translators (NAT)s), was previously released as IETF standard
- * <A HREF="http://www.ietf.org/rfc/rfc3489.txt">RFC 3489</A>, but since
- * then it has been revised into the following:
- * - <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-behave-rfc3489bis-06.txt">
- * <B>draft-ietf-behave-rfc3489bis-06</b></A> for the main STUN
- * specification,
- * - <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-behave-turn-03.txt">
- * <B>draft-ietf-behave-turn-03</B></A> for TURN usage of STUN,
- * - and several other drafts explaining other STUN usages.
+ * Translators (NAT)s), is a lightweight protocol that serves as a tool for
+ * application protocols in dealing with NAT traversal. It allows a client
+ * to determine the IP address and port allocated to them by a NAT and to
+ * keep NAT bindings open.
*
* The PJNATH library provides facilities to support both the core
* <B>STUN-bis</B> specification and the <B>TURN</B> usage of STUN,
@@ -133,6 +121,19 @@ PJ_END_DECL
* to the STUN components for processing. and it must supply the STUN
* components with callback to send outgoing messages.
*
+ *
+ * \subsection PJNATH_STUN_REF STUN Reference
+ *
+ * References for STUN:
+ *
+ * - <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-behave-rfc3489bis-06.txt">
+ * <B>draft-ietf-behave-rfc3489bis-06</b></A>: Session Traversal
+ * Utilities for (NAT) (STUN),
+ * - <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-behave-turn-03.txt">
+ * <B>draft-ietf-behave-turn-03</B></A>: Obtaining Relay Addresses
+ * from Simple Traversal Underneath NAT (STUN)
+ * - Obsoleted: <A HREF="http://www.ietf.org/rfc/rfc3489.txt">RFC 3489</A>.
+ *
* \n
*
* \section PJNATH_ICE ICE Implementation
@@ -170,6 +171,14 @@ PJ_END_DECL
* - the highest abstraction is ICE media transport, which maintains
* ICE stream transport and provides SDP translations to be used
* for SIP offer/answer exchanges.
+ *
+ * \subsection PJNATH_ICE_REF Reference
+ *
+ * References for ICE:
+ * - <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-mmusic-ice-15.txt">
+ * <B>draft-ietf-mmusic-ice-15.txt</B></A>: Interactive Connectivity
+ * Establishment (ICE): A Methodology for Network Address Translator
+ * (NAT) Traversal for Offer/Answer Protocols
*/
/**
diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c
index ec87a5c9..09617965 100644
--- a/pjnath/src/pjnath/ice_session.c
+++ b/pjnath/src/pjnath/ice_session.c
@@ -56,6 +56,12 @@ static const char *clist_state_name[] =
"Completed"
};
+static const char *role_names[] =
+{
+ "Controlled",
+ "Controlling"
+};
+
#define CHECK_NAME_LEN 128
#define LOG4(expr) PJ_LOG(4,expr)
#define LOG5(expr) PJ_LOG(4,expr)
@@ -196,6 +202,8 @@ PJ_DEF(pj_status_t) pj_ice_sess_create(pj_stun_config *stun_cfg,
ice = PJ_POOL_ZALLOC_T(pool, pj_ice_sess);
ice->pool = pool;
ice->role = role;
+ ice->tie_breaker.u32.hi = pj_rand();
+ ice->tie_breaker.u32.lo = pj_rand();
pj_ansi_snprintf(ice->obj_name, sizeof(ice->obj_name),
name, ice);
@@ -237,9 +245,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_create(pj_stun_config *stun_cfg,
LOG4((ice->obj_name,
"ICE session created, comp_cnt=%d, role is %s agent",
- comp_cnt,
- (ice->role==PJ_ICE_SESS_ROLE_CONTROLLING ?
- "controlling":"controlled")));
+ comp_cnt, role_names[ice->role]));
return PJ_SUCCESS;
}
@@ -293,6 +299,23 @@ PJ_DEF(pj_status_t) pj_ice_sess_destroy(pj_ice_sess *ice)
}
+/*
+ * Change session role.
+ */
+PJ_DEF(pj_status_t) pj_ice_sess_change_role(pj_ice_sess *ice,
+ pj_ice_sess_role new_role)
+{
+ PJ_ASSERT_RETURN(ice, PJ_EINVAL);
+
+ if (new_role != ice->role) {
+ ice->role = new_role;
+ LOG4((ice->obj_name, "Role changed to %s", role_names[new_role]));
+ }
+
+ return PJ_SUCCESS;
+}
+
+
/* Find component by ID */
static pj_ice_sess_comp *find_comp(const pj_ice_sess *ice, unsigned comp_id)
{
diff --git a/pjnath/src/pjnath/ice_strans.c b/pjnath/src/pjnath/ice_strans.c
index ab6524a8..378d13a4 100644
--- a/pjnath/src/pjnath/ice_strans.c
+++ b/pjnath/src/pjnath/ice_strans.c
@@ -60,6 +60,10 @@ static void stun_on_request_complete(pj_stun_session *sess,
pj_stun_tx_data *tdata,
const pj_stun_msg *response);
+/* Keep-alive timer */
+static void start_ka_timer(pj_ice_strans *ice_st);
+static void stop_ka_timer(pj_ice_strans *ice_st);
+
/* Utility: print error */
#if PJ_LOG_MAX_LEVEL >= 3
static void ice_st_perror(pj_ice_strans *ice_st, const char *title,
@@ -125,6 +129,9 @@ static void destroy_ice_st(pj_ice_strans *ice_st, pj_status_t reason)
PJ_LOG(4,(obj_name, "ICE stream transport shutting down"));
}
+ /* Kill keep-alive timer, if any */
+ stop_ka_timer(ice_st);
+
/* Destroy ICE if we have ICE */
if (ice_st->ice) {
pj_ice_sess_destroy(ice_st->ice);
@@ -197,7 +204,6 @@ PJ_DEF(pj_status_t) pj_ice_strans_set_stun_srv( pj_ice_strans *ice_st,
return PJ_SUCCESS;
}
-
/* Add new candidate */
static pj_status_t add_cand( pj_ice_strans *ice_st,
pj_ice_strans_comp *comp,
@@ -505,6 +511,84 @@ static void destroy_component(pj_ice_strans_comp *comp)
}
+/* STUN keep-alive timer callback */
+static void ka_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te)
+{
+ pj_ice_strans *ice_st = (pj_ice_strans*)te->user_data;
+ unsigned i;
+ pj_status_t status;
+
+ PJ_UNUSED_ARG(th);
+
+ ice_st->ka_timer.id = PJ_FALSE;
+
+ for (i=0; i<ice_st->comp_cnt; ++i) {
+ pj_ice_strans_comp *comp = ice_st->comp[i];
+ pj_stun_tx_data *tdata;
+ unsigned j;
+
+ /* Does this component have STUN server reflexive candidate? */
+ for (j=0; j<comp->cand_cnt; ++j) {
+ if (comp->cand_list[j].type == PJ_ICE_CAND_TYPE_SRFLX)
+ break;
+ }
+ if (j == comp->cand_cnt)
+ continue;
+
+ /* Create STUN binding request */
+ status = pj_stun_session_create_req(comp->stun_sess,
+ PJ_STUN_BINDING_REQUEST, &tdata);
+ if (status != PJ_SUCCESS)
+ continue;
+
+ /* tdata->user_data is NULL for keep-alive */
+ tdata->user_data = NULL;
+
+ /* Send STUN binding request */
+ PJ_LOG(5,(ice_st->obj_name, "Sending STUN keep-alive"));
+ status = pj_stun_session_send_msg(comp->stun_sess, PJ_FALSE,
+ &ice_st->stun_srv,
+ sizeof(pj_sockaddr_in), tdata);
+ }
+
+ /* Start next timer */
+ start_ka_timer(ice_st);
+}
+
+/* Start STUN keep-alive timer */
+static void start_ka_timer(pj_ice_strans *ice_st)
+{
+ pj_time_val delay;
+
+ /* Skip if timer is already running */
+ if (ice_st->ka_timer.id != PJ_FALSE)
+ return;
+
+ delay.sec = 20;
+ delay.msec = 0;
+
+ ice_st->ka_timer.cb = &ka_timer_cb;
+ ice_st->ka_timer.user_data = ice_st;
+
+ if (pj_timer_heap_schedule(ice_st->stun_cfg.timer_heap,
+ &ice_st->ka_timer, &delay)==PJ_SUCCESS)
+ {
+ ice_st->ka_timer.id = PJ_TRUE;
+ }
+}
+
+
+/* Stop STUN keep-alive timer */
+static void stop_ka_timer(pj_ice_strans *ice_st)
+{
+ /* Skip if timer is already stop */
+ if (ice_st->ka_timer.id == PJ_FALSE)
+ return;
+
+ pj_timer_heap_cancel(ice_st->stun_cfg.timer_heap, &ice_st->ka_timer);
+ ice_st->ka_timer.id = PJ_FALSE;
+}
+
/*
* Add STUN mapping to a component.
@@ -830,21 +914,15 @@ PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st,
return pj_ice_sess_send_data(ice_st->ice, comp_id, data, data_len);
}
-#if 1
- PJ_UNUSED_ARG(pkt_size);
- PJ_UNUSED_ARG(status);
-
- /* Otherwise return error */
- return PJNATH_EICEINPROGRESS;
-#else
- /* Otherwise send direcly with the socket */
+ /* Otherwise send direcly with the socket. This is for compatibility
+ * with remote that doesn't support ICE.
+ */
pkt_size = data_len;
status = pj_ioqueue_sendto(comp->key, &comp->write_op,
data, &pkt_size, 0,
dst_addr, dst_addr_len);
return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status;
-#endif
}
/*
@@ -943,6 +1021,11 @@ static void stun_on_request_complete(pj_stun_session *sess,
comp = (pj_ice_strans_comp*) pj_stun_session_get_user_data(sess);
cand = (pj_ice_strans_cand*) tdata->user_data;
+ if (cand == NULL) {
+ /* This is keep-alive */
+ return;
+ }
+
/* Decrement pending count for this component */
pj_assert(comp->pending_cnt > 0);
comp->pending_cnt--;
@@ -980,5 +1063,8 @@ static void stun_on_request_complete(pj_stun_session *sess,
/* Set this candidate as the default candidate */
comp->default_cand = (cand - comp->cand_list);
comp->last_status = PJ_SUCCESS;
+
+ /* We have STUN, so we must start the keep-alive timer */
+ start_ka_timer(comp->ice_st);
}
diff --git a/pjnath/src/pjnath/stun_msg.c b/pjnath/src/pjnath/stun_msg.c
index 4e9c209d..072a7a1b 100644
--- a/pjnath/src/pjnath/stun_msg.c
+++ b/pjnath/src/pjnath/stun_msg.c
@@ -71,6 +71,7 @@ static struct
{ PJ_STUN_SC_CONNECTION_FAILURE, "Connection Failure"},
{ PJ_STUN_SC_CONNECTION_TIMEOUT, "Connection Timeout"},
{ PJ_STUN_SC_ALLOCATION_QUOTA_REACHED, "Allocation Quota Reached"},
+ { PJ_STUN_SC_ROLE_CONFLICT, "Role Conflict"},
{ PJ_STUN_SC_SERVER_ERROR, "Server Error"},
{ PJ_STUN_SC_INSUFFICIENT_CAPACITY, "Insufficient Capacity"},
{ PJ_STUN_SC_GLOBAL_FAILURE, "Global Failure"}
@@ -85,7 +86,6 @@ struct attr_desc
void **p_attr);
pj_status_t (*encode_attr)(const void *a, pj_uint8_t *buf,
unsigned len, unsigned *printed);
-
};
static pj_status_t decode_sockaddr_attr(pj_pool_t *pool,
@@ -122,6 +122,11 @@ static pj_status_t decode_uint_attr(pj_pool_t *pool,
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_uint64_attr(pj_pool_t *pool,
+ const pj_uint8_t *buf,
+ void **p_attr);
+static pj_status_t encode_uint64_attr(const void *a, pj_uint8_t *buf,
+ unsigned len, unsigned *printed);
static pj_status_t decode_binary_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
void **p_attr);
@@ -429,6 +434,18 @@ static struct attr_desc extended_attr_desc[] =
"FINGERPRINT",
&decode_uint_attr,
&encode_uint_attr
+ },
+ {
+ /* PJ_STUN_ATTR_ICE_CONTROLLED, */
+ "ICE-CCONTROLLED",
+ &decode_uint64_attr,
+ &encode_uint64_attr
+ },
+ {
+ /* PJ_STUN_ATTR_ICE_CONTROLLING, */
+ "ICE-CCONTROLLING",
+ &decode_uint64_attr,
+ &encode_uint64_attr
}
};
@@ -551,14 +568,69 @@ PJ_DEF(pj_str_t) pj_stun_get_err_reason(int err_code)
}
+//////////////////////////////////////////////////////////////////////////////
+
#define INIT_ATTR(a,t,l) (a)->hdr.type=(pj_uint16_t)(t), \
(a)->hdr.length=(pj_uint16_t)(l)
#define ATTR_HDR_LEN 4
-#define getval16(p, pos) (pj_uint16_t)(((p)[(pos)] << 8) | \
- ((p)[(pos) + 1] << 0))
+static pj_uint16_t GETVAL16H(const pj_uint8_t *buf, unsigned pos)
+{
+ return (pj_uint16_t) ((buf[pos + 0] << 8) | \
+ (buf[pos + 1] << 0));
+}
+
+static pj_uint16_t GETVAL16N(const pj_uint8_t *buf, unsigned pos)
+{
+ return pj_htons(GETVAL16H(buf,pos));
+}
+
+static void PUTVAL16H(pj_uint8_t *buf, unsigned pos, pj_uint16_t hval)
+{
+ buf[pos+0] = (pj_uint8_t) ((hval & 0xFF00) >> 8);
+ buf[pos+1] = (pj_uint8_t) ((hval & 0x00FF) >> 0);
+}
+static pj_uint32_t GETVAL32H(const pj_uint8_t *buf, unsigned pos)
+{
+ return (pj_uint32_t) ((buf[pos + 0] << 24UL) | \
+ (buf[pos + 1] << 16UL) | \
+ (buf[pos + 2] << 8UL) | \
+ (buf[pos + 3] << 0UL));
+}
+
+static pj_uint32_t GETVAL32N(const pj_uint8_t *buf, unsigned pos)
+{
+ return pj_htonl(GETVAL32H(buf,pos));
+}
+
+static void PUTVAL32H(pj_uint8_t *buf, unsigned pos, pj_uint32_t hval)
+{
+ buf[pos+0] = (pj_uint8_t) ((hval & 0xFF000000UL) >> 24);
+ buf[pos+1] = (pj_uint8_t) ((hval & 0x00FF0000UL) >> 16);
+ buf[pos+2] = (pj_uint8_t) ((hval & 0x0000FF00UL) >> 8);
+ buf[pos+3] = (pj_uint8_t) ((hval & 0x000000FFUL) >> 0);
+}
+
+static void GETVAL64H(const pj_uint8_t *buf, unsigned pos, pj_timestamp *ts)
+{
+ ts->u32.hi = GETVAL32H(buf, pos);
+ ts->u32.lo = GETVAL32H(buf, pos+4);
+}
+
+static void PUTVAL64H(pj_uint8_t *buf, unsigned pos, const pj_timestamp *ts)
+{
+ PUTVAL32H(buf, pos, ts->u32.hi);
+ PUTVAL32H(buf, pos+4, ts->u32.lo);
+}
+
+
+static void GETATTRHDR(const pj_uint8_t *buf, pj_stun_attr_hdr *hdr)
+{
+ hdr->type = GETVAL16H(buf, 0);
+ hdr->length = GETVAL16H(buf, 2);
+}
//////////////////////////////////////////////////////////////////////////////
/*
@@ -626,11 +698,7 @@ static pj_status_t decode_sockaddr_attr(pj_pool_t *pool,
/* Create the attribute */
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_sockaddr_attr);
- pj_memcpy(attr, buf, ATTR_HDR_LEN);
-
- /* Convert to host byte order */
- attr->hdr.type = pj_ntohs(attr->hdr.type);
- attr->hdr.length = pj_ntohs(attr->hdr.length);
+ GETATTRHDR(buf, &attr->hdr);
/* Check that the attribute length is valid */
if (attr->hdr.length != STUN_GENERIC_IP_ADDR_LEN)
@@ -645,8 +713,8 @@ static pj_status_t decode_sockaddr_attr(pj_pool_t *pool,
/* Get port and address */
pj_sockaddr_in_init(&attr->sockaddr.ipv4, NULL, 0);
- pj_memcpy(&attr->sockaddr.ipv4.sin_port, buf+ATTR_HDR_LEN+2, 2);
- pj_memcpy(&attr->sockaddr.ipv4.sin_addr, buf+ATTR_HDR_LEN+4, 4);
+ attr->sockaddr.ipv4.sin_port = GETVAL16N(buf, ATTR_HDR_LEN+2);
+ attr->sockaddr.ipv4.sin_addr.s_addr = GETVAL32N(buf, ATTR_HDR_LEN+4);
/* Done */
*p_attr = attr;
@@ -660,32 +728,13 @@ static pj_status_t decode_xored_sockaddr_attr(pj_pool_t *pool,
void **p_attr)
{
pj_stun_sockaddr_attr *attr;
- pj_uint32_t val;
-
- /* Create the attribute */
- attr = PJ_POOL_ZALLOC_T(pool, pj_stun_sockaddr_attr);
- pj_memcpy(attr, buf, ATTR_HDR_LEN);
-
- /* Convert to host byte order */
- attr->hdr.type = pj_ntohs(attr->hdr.type);
- attr->hdr.length = pj_ntohs(attr->hdr.length);
-
- /* Check that the attribute length is valid */
- if (attr->hdr.length != STUN_GENERIC_IP_ADDR_LEN)
- return PJNATH_ESTUNINATTRLEN;
-
- /* Check address family */
- val = *(pj_uint8_t*)(buf + ATTR_HDR_LEN + 1);
-
- /* Check address family is valid (only supports ipv4 for now) */
- if (val != 1)
- return PJNATH_ESTUNIPV6NOTSUPP;
+ pj_status_t status;
- /* Get port and address */
- pj_sockaddr_in_init(&attr->sockaddr.ipv4, NULL, 0);
- pj_memcpy(&attr->sockaddr.ipv4.sin_port, buf+ATTR_HDR_LEN+2, 2);
- pj_memcpy(&attr->sockaddr.ipv4.sin_addr, buf+ATTR_HDR_LEN+4, 4);
+ status = decode_sockaddr_attr(pool, buf, &attr);
+ if (status != PJ_SUCCESS)
+ return status;
+ attr->xor_ed = PJ_TRUE;
attr->sockaddr.ipv4.sin_port ^= pj_htons(0x2112);
attr->sockaddr.ipv4.sin_addr.s_addr ^= pj_htonl(0x2112A442);
@@ -705,16 +754,13 @@ static pj_status_t encode_sockaddr_attr(const void *a, pj_uint8_t *buf,
pj_uint8_t *start_buf = buf;
const pj_stun_sockaddr_attr *ca =
(const pj_stun_sockaddr_attr *)a;
- pj_stun_sockaddr_attr *attr;
if (len < ATTR_LEN)
return PJ_ETOOSMALL;
/* Copy and convert headers to network byte order */
- pj_memcpy(buf, a, ATTR_HDR_LEN);
- attr = (pj_stun_sockaddr_attr*) buf;
- attr->hdr.type = pj_htons(attr->hdr.type);
- attr->hdr.length = pj_htons((pj_uint16_t)STUN_GENERIC_IP_ADDR_LEN);
+ PUTVAL16H(buf, 0, ca->hdr.type);
+ PUTVAL16H(buf, 2, STUN_GENERIC_IP_ADDR_LEN);
buf += ATTR_HDR_LEN;
/* Ignored */
@@ -819,13 +865,7 @@ static pj_status_t decode_string_attr(pj_pool_t *pool,
/* Create the attribute */
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_string_attr);
-
- /* Copy the header */
- pj_memcpy(attr, buf, ATTR_HDR_LEN);
-
- /* Convert to host byte order */
- attr->hdr.type = pj_ntohs(attr->hdr.type);
- attr->hdr.length = pj_ntohs(attr->hdr.length);
+ GETATTRHDR(buf, &attr->hdr);
/* Get pointer to the string in the message */
value.ptr = ((char*)buf + ATTR_HDR_LEN);
@@ -847,7 +887,6 @@ static pj_status_t encode_string_attr(const void *a, pj_uint8_t *buf,
{
const pj_stun_string_attr *ca =
(const pj_stun_string_attr*)a;
- pj_stun_attr_hdr *attr;
/* Calculated total attr_len (add padding if necessary) */
*printed = (ca->value.slen + ATTR_HDR_LEN + 3) & (~3);
@@ -856,16 +895,9 @@ static pj_status_t encode_string_attr(const void *a, pj_uint8_t *buf,
return PJ_ETOOSMALL;
}
- /* Copy header */
- pj_memcpy(buf, a, ATTR_HDR_LEN);
- attr = (pj_stun_attr_hdr*)buf;
-
- /* Set the correct length */
- attr->length = (pj_uint16_t) ca->value.slen;
-
- /* Convert to network byte order */
- attr->type = pj_htons(attr->type);
- attr->length = pj_htons(attr->length);
+ PUTVAL16H(buf, 0, ca->hdr.type);
+ PUTVAL16H(buf, 2, (pj_uint16_t)ca->value.slen);
+
/* Copy the string */
pj_memcpy(buf+ATTR_HDR_LEN, ca->value.ptr, ca->value.slen);
@@ -929,11 +961,7 @@ static pj_status_t decode_empty_attr(pj_pool_t *pool,
/* Create the attribute */
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_empty_attr);
- pj_memcpy(attr, buf, ATTR_HDR_LEN);
-
- /* Convert to host byte order */
- attr->hdr.type = pj_ntohs(attr->hdr.type);
- attr->hdr.length = pj_ntohs(attr->hdr.length);
+ GETATTRHDR(buf, &attr->hdr);
/* Check that the attribute length is valid */
if (attr->hdr.length != 0)
@@ -949,16 +977,13 @@ static pj_status_t decode_empty_attr(pj_pool_t *pool,
static pj_status_t encode_empty_attr(const void *a, pj_uint8_t *buf,
unsigned len, unsigned *printed)
{
- pj_stun_empty_attr *attr;
+ const pj_stun_empty_attr *ca = (pj_stun_empty_attr*)a;
if (len < ATTR_HDR_LEN)
return PJ_ETOOSMALL;
- /* Copy and convert attribute to network byte order */
- pj_memcpy(buf, a, ATTR_HDR_LEN);
- attr = (pj_stun_empty_attr*) buf;
- attr->hdr.type = pj_htons(attr->hdr.type);
- attr->hdr.length = 0;
+ PUTVAL16H(buf, 0, ca->hdr.type);
+ PUTVAL16H(buf, 2, 0);
/* Done */
*printed = ATTR_HDR_LEN;
@@ -971,7 +996,6 @@ static pj_status_t encode_empty_attr(const void *a, pj_uint8_t *buf,
/*
* STUN generic 32bit integer attribute.
*/
-#define STUN_UINT_LEN 4
/*
* Create a STUN generic 32bit value attribute.
@@ -987,7 +1011,7 @@ pj_stun_uint_attr_create(pj_pool_t *pool,
PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL);
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint_attr);
- INIT_ATTR(attr, attr_type, STUN_UINT_LEN);
+ INIT_ATTR(attr, attr_type, 4);
attr->value = value;
*p_attr = attr;
@@ -1016,26 +1040,16 @@ static pj_status_t decode_uint_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
void **p_attr)
{
- enum
- {
- ATTR_LEN = STUN_UINT_LEN + ATTR_HDR_LEN
- };
pj_stun_uint_attr *attr;
- /* Check that the struct address is valid */
- pj_assert(sizeof(pj_stun_uint_attr) == ATTR_LEN);
-
/* Create the attribute */
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint_attr);
- pj_memcpy(attr, buf, ATTR_LEN);
+ GETATTRHDR(buf, &attr->hdr);
- /* Convert to host byte order */
- attr->hdr.type = pj_ntohs(attr->hdr.type);
- attr->hdr.length = pj_ntohs(attr->hdr.length);
- attr->value = pj_ntohl(attr->value);
+ attr->value = GETVAL32H(buf, 4);
/* Check that the attribute length is valid */
- if (attr->hdr.length != STUN_UINT_LEN)
+ if (attr->hdr.length != 4)
return PJNATH_ESTUNINATTRLEN;
/* Done */
@@ -1048,36 +1062,111 @@ static pj_status_t decode_uint_attr(pj_pool_t *pool,
static pj_status_t encode_uint_attr(const void *a, pj_uint8_t *buf,
unsigned len, unsigned *printed)
{
- enum
- {
- ATTR_LEN = STUN_UINT_LEN + ATTR_HDR_LEN
- };
- pj_stun_uint_attr *attr;
+ const pj_stun_uint_attr *ca = (const pj_stun_uint_attr*)a;
- if (len < ATTR_LEN)
+ if (len < 8)
return PJ_ETOOSMALL;
- /* Copy and convert attribute to network byte order */
- pj_memcpy(buf, a, ATTR_LEN);
- attr = (pj_stun_uint_attr*) buf;
- attr->hdr.type = pj_htons(attr->hdr.type);
- pj_assert(attr->hdr.length == STUN_UINT_LEN);
- attr->hdr.length = pj_htons(STUN_UINT_LEN);
- attr->value = pj_htonl(attr->value);
+ PUTVAL16H(buf, 0, ca->hdr.type);
+ PUTVAL16H(buf, 2, (pj_uint16_t)4);
+ PUTVAL32H(buf, 4, ca->value);
+
+ /* Done */
+ *printed = 8;
+
+ return PJ_SUCCESS;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+/*
+ * Create a STUN generic 64bit value attribute.
+ */
+PJ_DEF(pj_status_t)
+pj_stun_uint64_attr_create(pj_pool_t *pool,
+ int attr_type,
+ const pj_timestamp *value,
+ pj_stun_uint64_attr **p_attr)
+{
+ pj_stun_uint64_attr *attr;
+
+ PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL);
+
+ attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint64_attr);
+ INIT_ATTR(attr, attr_type, 4);
+
+ if (value) {
+ attr->value.u32.hi = value->u32.hi;
+ attr->value.u32.lo = value->u32.lo;
+ }
+
+ *p_attr = attr;
+
+ return PJ_SUCCESS;
+}
+
+/* Create and add STUN generic 64bit value attribute to the message. */
+PJ_DEF(pj_status_t) pj_stun_msg_add_uint64_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int attr_type,
+ const pj_timestamp *value)
+{
+ pj_stun_uint64_attr *attr = NULL;
+ pj_status_t status;
+
+ status = pj_stun_uint64_attr_create(pool, attr_type, value, &attr);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ return pj_stun_msg_add_attr(msg, &attr->hdr);
+}
+
+static pj_status_t decode_uint64_attr(pj_pool_t *pool,
+ const pj_uint8_t *buf,
+ void **p_attr)
+{
+ pj_stun_uint64_attr *attr;
+
+ /* Create the attribute */
+ attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint64_attr);
+ GETATTRHDR(buf, &attr->hdr);
+
+ if (attr->hdr.length != 8)
+ return PJNATH_ESTUNINATTRLEN;
+
+ GETVAL64H(buf, 4, &attr->value);
+
+ /* Done */
+ *p_attr = attr;
+
+ return PJ_SUCCESS;
+}
+
+
+static pj_status_t encode_uint64_attr(const void *a, pj_uint8_t *buf,
+ unsigned len, unsigned *printed)
+{
+ const pj_stun_uint64_attr *ca = (const pj_stun_uint64_attr*)a;
+
+ if (len < 12)
+ return PJ_ETOOSMALL;
+
+ PUTVAL16H(buf, 0, ca->hdr.type);
+ PUTVAL16H(buf, 2, ca->hdr.length);
+ PUTVAL64H(buf, 4, &ca->value);
/* Done */
- *printed = ATTR_LEN;
+ *printed = 12;
return PJ_SUCCESS;
}
+
//////////////////////////////////////////////////////////////////////////////
/*
* STUN MESSAGE-INTEGRITY attribute.
*/
-#define STUN_MSG_INTEGRITY_LEN 20
-
/*
* Create a STUN MESSAGE-INTEGRITY attribute.
*/
@@ -1090,7 +1179,7 @@ pj_stun_msgint_attr_create(pj_pool_t *pool,
PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL);
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_msgint_attr);
- INIT_ATTR(attr, PJ_STUN_ATTR_MESSAGE_INTEGRITY, STUN_MSG_INTEGRITY_LEN);
+ INIT_ATTR(attr, PJ_STUN_ATTR_MESSAGE_INTEGRITY, 20);
*p_attr = attr;
@@ -1115,25 +1204,19 @@ static pj_status_t decode_msgint_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
void **p_attr)
{
- enum
- {
- ATTR_LEN = STUN_MSG_INTEGRITY_LEN + ATTR_HDR_LEN
- };
pj_stun_msgint_attr *attr;
- /* Check that struct size is valid */
- pj_assert(sizeof(pj_stun_msgint_attr)==ATTR_LEN);
-
/* Create attribute */
attr = PJ_POOL_ZALLOC_T(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);
+ GETATTRHDR(buf, &attr->hdr);
/* Check that the attribute length is valid */
- if (attr->hdr.length != STUN_MSG_INTEGRITY_LEN)
+ if (attr->hdr.length != 20)
return PJNATH_ESTUNINATTRLEN;
+ /* Copy hmac */
+ pj_memcpy(attr->hmac, buf+4, 20);
+
/* Done */
*p_attr = attr;
return PJ_SUCCESS;
@@ -1143,24 +1226,19 @@ static pj_status_t decode_msgint_attr(pj_pool_t *pool,
static pj_status_t encode_msgint_attr(const void *a, pj_uint8_t *buf,
unsigned len, unsigned *printed)
{
- enum
- {
- ATTR_LEN = STUN_MSG_INTEGRITY_LEN + ATTR_HDR_LEN
- };
- pj_stun_msgint_attr *attr;
+ const pj_stun_msgint_attr *ca = (const pj_stun_msgint_attr*)a;
- if (len < ATTR_LEN)
+ if (len < 24)
return PJ_ETOOSMALL;
/* Copy and convert attribute to network byte order */
- pj_memcpy(buf, a, ATTR_LEN);
- attr = (pj_stun_msgint_attr*) buf;
- attr->hdr.type = pj_htons(attr->hdr.type);
- pj_assert(attr->hdr.length == STUN_MSG_INTEGRITY_LEN);
- attr->hdr.length = pj_htons(STUN_MSG_INTEGRITY_LEN);
+ PUTVAL16H(buf, 0, ca->hdr.type);
+ PUTVAL16H(buf, 2, ca->hdr.length);
+
+ pj_memcpy(buf+4, ca->hmac, 20);
/* Done */
- *printed = ATTR_LEN;
+ *printed = 24;
return PJ_SUCCESS;
}
@@ -1197,8 +1275,7 @@ pj_stun_errcode_attr_create(pj_pool_t *pool,
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_errcode_attr);
INIT_ATTR(attr, PJ_STUN_ATTR_ERROR_CODE, 4+err_reason->slen);
- attr->err_class = (pj_uint8_t)(err_code / 100);
- attr->number = (pj_uint8_t) (err_code % 100);
+ attr->err_code = err_code;
pj_strdup(pool, &attr->reason, err_reason);
*p_attr = attr;
@@ -1232,13 +1309,9 @@ static pj_status_t decode_errcode_attr(pj_pool_t *pool,
/* Create the attribute */
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_errcode_attr);
+ GETATTRHDR(buf, &attr->hdr);
- /* Copy the header */
- pj_memcpy(attr, buf, ATTR_HDR_LEN + 4);
-
- /* Convert to host byte order */
- attr->hdr.type = pj_ntohs(attr->hdr.type);
- attr->hdr.length = pj_ntohs(attr->hdr.length);
+ attr->err_code = buf[6] * 100 + buf[7];
/* Get pointer to the string in the message */
value.ptr = ((char*)buf + ATTR_HDR_LEN + 4);
@@ -1259,21 +1332,16 @@ static pj_status_t encode_errcode_attr(const void *a, pj_uint8_t *buf,
{
const pj_stun_errcode_attr *ca =
(const pj_stun_errcode_attr*)a;
- pj_stun_errcode_attr *attr;
if (len < ATTR_HDR_LEN + 4 + (unsigned)ca->reason.slen)
return PJ_ETOOSMALL;
/* Copy and convert attribute to network byte order */
- pj_memcpy(buf, ca, ATTR_HDR_LEN + 4);
-
- /* Update length */
- attr = (pj_stun_errcode_attr*) buf;
- attr->hdr.length = (pj_uint16_t)(4 + ca->reason.slen);
-
- /* Convert fiends to network byte order */
- attr->hdr.type = pj_htons(attr->hdr.type);
- attr->hdr.length = pj_htons(attr->hdr.length);
+ PUTVAL16H(buf, 0, ca->hdr.type);
+ PUTVAL16H(buf, 2, (pj_uint16_t)(4 + ca->reason.slen));
+ PUTVAL16H(buf, 4, 0);
+ buf[6] = (pj_uint8_t)(ca->err_code / 100);
+ buf[7] = (pj_uint8_t)(ca->err_code % 100);
/* Copy error string */
pj_memcpy(buf + ATTR_HDR_LEN + 4, ca->reason.ptr, ca->reason.slen);
@@ -1355,11 +1423,8 @@ static pj_status_t decode_unknown_attr(pj_pool_t *pool,
unsigned i;
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_unknown_attr);
- pj_memcpy(attr, buf, ATTR_HDR_LEN);
-
- attr->hdr.type = pj_ntohs(attr->hdr.type);
- attr->hdr.length = pj_ntohs(attr->hdr.length);
-
+ GETATTRHDR(buf, &attr->hdr);
+
attr->attr_count = (attr->hdr.length >> 1);
if (attr->attr_count > PJ_STUN_MAX_ATTR)
return PJ_ETOOMANY;
@@ -1380,7 +1445,6 @@ static pj_status_t encode_unknown_attr(const void *a, pj_uint8_t *buf,
unsigned len, unsigned *printed)
{
const pj_stun_unknown_attr *ca = (const pj_stun_unknown_attr*) a;
- pj_stun_unknown_attr *attr;
pj_uint16_t *dst_unk_attr;
unsigned i;
@@ -1388,21 +1452,13 @@ static pj_status_t encode_unknown_attr(const void *a, pj_uint8_t *buf,
if (len < ATTR_HDR_LEN + (ca->attr_count << 1))
return PJ_ETOOSMALL;
- /* Copy to message */
- pj_memcpy(buf, ca, ATTR_HDR_LEN);
-
- /* Set the correct length */
- attr = (pj_stun_unknown_attr *) buf;
- attr->hdr.length = (pj_uint16_t)(ca->attr_count << 1);
-
- /* Convert to network byte order */
- attr->hdr.type = pj_htons(attr->hdr.type);
- attr->hdr.length = pj_htons(attr->hdr.length);
+ PUTVAL16H(buf, 0, ca->hdr.type);
+ PUTVAL16H(buf, 2, (pj_uint16_t)(ca->attr_count << 1));
/* Copy individual attribute */
dst_unk_attr = (pj_uint16_t*)(buf + ATTR_HDR_LEN);
for (i=0; i < ca->attr_count; ++i, ++dst_unk_attr) {
- *dst_unk_attr = pj_htons(attr->attrs[i]);
+ *dst_unk_attr = pj_htons(ca->attrs[i]);
}
/* Done */
@@ -1432,7 +1488,7 @@ pj_stun_binary_attr_create(pj_pool_t *pool,
PJ_ASSERT_RETURN(pool && attr_type && p_attr, PJ_EINVAL);
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_binary_attr);
- INIT_ATTR(attr, attr_type, sizeof(pj_stun_binary_attr));
+ INIT_ATTR(attr, attr_type, length);
if (data && length) {
attr->length = length;
@@ -1474,13 +1530,7 @@ static pj_status_t decode_binary_attr(pj_pool_t *pool,
/* Create the attribute */
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_binary_attr);
-
- /* Copy the header */
- pj_memcpy(attr, buf, ATTR_HDR_LEN);
-
- /* Convert to host byte order */
- attr->hdr.type = pj_ntohs(attr->hdr.type);
- attr->hdr.length = pj_ntohs(attr->hdr.length);
+ GETATTRHDR(buf, &attr->hdr);
/* Copy the data to the attribute */
attr->length = attr->hdr.length;
@@ -1499,23 +1549,14 @@ static pj_status_t encode_binary_attr(const void *a, pj_uint8_t *buf,
unsigned len, unsigned *printed)
{
const pj_stun_binary_attr *ca = (const pj_stun_binary_attr*)a;
- pj_stun_attr_hdr *attr;
/* Calculated total attr_len (add padding if necessary) */
*printed = (ca->length + ATTR_HDR_LEN + 3) & (~3);
if (len < *printed)
return PJ_ETOOSMALL;
- /* Copy header */
- pj_memcpy(buf, a, ATTR_HDR_LEN);
-
- /* Set the correct length */
- attr = (pj_stun_attr_hdr*)buf;
- attr->length = (pj_uint16_t) ca->length;
-
- /* Convert to network byte order */
- attr->type = pj_htons(attr->type);
- attr->length = pj_htons(attr->length);
+ PUTVAL16H(buf, 0, ca->hdr.type);
+ PUTVAL16H(buf, 2, (pj_uint16_t) ca->length);
/* Copy the data */
pj_memcpy(buf+ATTR_HDR_LEN, ca->data, ca->length);
@@ -1582,20 +1623,6 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_attr(pj_stun_msg *msg,
}
-PJ_INLINE(pj_uint16_t) GET_VAL16(const pj_uint8_t *pdu, unsigned pos)
-{
- return (pj_uint16_t) ((pdu[pos] << 8) + pdu[pos+1]);
-}
-
-PJ_INLINE(pj_uint32_t) GET_VAL32(const pj_uint8_t *pdu, unsigned pos)
-{
- return (pdu[pos+0] << 24) +
- (pdu[pos+1] << 16) +
- (pdu[pos+2] << 8) +
- (pdu[pos+3]);
-}
-
-
/*
* Check that the PDU is potentially a valid STUN message.
*/
@@ -1614,7 +1641,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_check(const pj_uint8_t *pdu, unsigned pdu_len,
return PJNATH_EINSTUNMSGTYPE;
/* Check the PDU length */
- msg_len = GET_VAL16(pdu, 2);
+ msg_len = GETVAL16H(pdu, 2);
if ((msg_len + 20 > pdu_len) ||
((options & PJ_STUN_IS_DATAGRAM) && msg_len + 20 != pdu_len))
{
@@ -1624,12 +1651,12 @@ PJ_DEF(pj_status_t) pj_stun_msg_check(const pj_uint8_t *pdu, unsigned pdu_len,
/* If magic is set, then there is great possibility that this is
* a STUN message.
*/
- if (GET_VAL32(pdu, 4) == PJ_STUN_MAGIC) {
+ if (GETVAL32H(pdu, 4) == PJ_STUN_MAGIC) {
/* Check if FINGERPRINT attribute is present */
- if (GET_VAL16(pdu, msg_len + 20) == PJ_STUN_ATTR_FINGERPRINT) {
- pj_uint16_t attr_len = GET_VAL16(pdu, msg_len + 22);
- pj_uint32_t fingerprint = GET_VAL32(pdu, msg_len + 24);
+ if (GETVAL16H(pdu, msg_len + 20) == PJ_STUN_ATTR_FINGERPRINT) {
+ pj_uint16_t attr_len = GETVAL16H(pdu, msg_len + 22);
+ pj_uint32_t fingerprint = GETVAL32H(pdu, msg_len + 24);
pj_uint32_t crc;
if (attr_len != 4)
diff --git a/pjnath/src/pjnath/stun_msg_dump.c b/pjnath/src/pjnath/stun_msg_dump.c
index 5e83958e..e888e91e 100644
--- a/pjnath/src/pjnath/stun_msg_dump.c
+++ b/pjnath/src/pjnath/stun_msg_dump.c
@@ -140,7 +140,7 @@ static int print_attr(char *buffer, unsigned length,
attr = (const pj_stun_errcode_attr*) ahdr;
len = pj_ansi_snprintf(p, end-p,
", err_code=%d, reason=\"%.*s\"\n",
- attr->err_class*100 + attr->number,
+ attr->err_code,
(int)attr->reason.slen,
attr->reason.ptr);
}
diff --git a/pjnath/src/pjnath/stun_transaction.c b/pjnath/src/pjnath/stun_transaction.c
index 66ff5b0f..69829919 100644
--- a/pjnath/src/pjnath/stun_transaction.c
+++ b/pjnath/src/pjnath/stun_transaction.c
@@ -284,14 +284,14 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx,
err_attr = (pj_stun_errcode_attr*)
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ERROR_CODE, 0);
- if (err_attr && err_attr->err_class <= 2) {
+ if (err_attr && err_attr->err_code <= 200) {
/* draft-ietf-behave-rfc3489bis-05.txt Section 8.3.2:
* Any response between 100 and 299 MUST result in the cessation
* of request retransmissions, but otherwise is discarded.
*/
PJ_LOG(4,(tsx->obj_name,
"STUN rx_msg() error: received provisional %d code (%.*s)",
- err_attr->err_class * 100 + err_attr->number,
+ err_attr->err_code,
(int)err_attr->reason.slen,
err_attr->reason.ptr));
return PJ_SUCCESS;
@@ -300,8 +300,7 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx,
if (err_attr == NULL) {
status = PJ_SUCCESS;
} else {
- status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_class * 100 +
- err_attr->number);
+ status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code);
}
/* Call callback */