diff options
Diffstat (limited to 'pjnath')
-rw-r--r-- | pjnath/include/pjnath/ice_session.h | 16 | ||||
-rw-r--r-- | pjnath/include/pjnath/ice_strans.h | 3 | ||||
-rw-r--r-- | pjnath/include/pjnath/stun_msg.h | 71 | ||||
-rw-r--r-- | pjnath/include/pjnath/types.h | 45 | ||||
-rw-r--r-- | pjnath/src/pjnath/ice_session.c | 29 | ||||
-rw-r--r-- | pjnath/src/pjnath/ice_strans.c | 106 | ||||
-rw-r--r-- | pjnath/src/pjnath/stun_msg.c | 419 | ||||
-rw-r--r-- | pjnath/src/pjnath/stun_msg_dump.c | 2 | ||||
-rw-r--r-- | pjnath/src/pjnath/stun_transaction.c | 7 |
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 */ |