Added ICE-CONTROLLING and ICE-CONTROLLED STUN attribute types
git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@1114 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
parent
33fcaa03c4
commit
919758f01f
|
@ -77,7 +77,8 @@ PJ_BEGIN_DECL
|
|||
|
||||
|
||||
/**
|
||||
* RTP packet header.
|
||||
* RTP packet header. Note that all RTP functions here will work with this
|
||||
* header in network byte order.
|
||||
*/
|
||||
#pragma pack(1)
|
||||
struct pjmedia_rtp_hdr
|
||||
|
@ -229,7 +230,7 @@ typedef struct pjmedia_rtp_status pjmedia_rtp_status;
|
|||
*
|
||||
* @param ses The session.
|
||||
* @param default_pt Default payload type.
|
||||
* @param sender_ssrc SSRC used for outgoing packets.
|
||||
* @param sender_ssrc SSRC used for outgoing packets, in host byte order.
|
||||
*
|
||||
* @return PJ_SUCCESS if successfull.
|
||||
*/
|
||||
|
@ -262,11 +263,16 @@ PJ_DECL(pj_status_t) pjmedia_rtp_encode_rtp( pjmedia_rtp_session *ses,
|
|||
* The decode function is guaranteed to point the payload to the correct
|
||||
* position regardless of any options present in the RTP packet.
|
||||
*
|
||||
* Note that this function does not modify the returned RTP header to
|
||||
* host byte order.
|
||||
*
|
||||
* @param ses The session.
|
||||
* @param pkt The received RTP packet.
|
||||
* @param pkt_len The length of the packet.
|
||||
* @param hdr Upon return will point to the location of the RTP header
|
||||
* inside the packet.
|
||||
* @param hdr Upon return will point to the location of the RTP
|
||||
* header inside the packet. Note that the RTP header
|
||||
* will be given back as is, meaning that the fields
|
||||
* will be in network byte order.
|
||||
* @param payload Upon return will point to the location of the
|
||||
* payload inside the packet.
|
||||
* @param payloadlen Upon return will indicate the size of the payload.
|
||||
|
@ -285,7 +291,8 @@ PJ_DECL(pj_status_t) pjmedia_rtp_decode_rtp( pjmedia_rtp_session *ses,
|
|||
* calculations.
|
||||
*
|
||||
* @param ses The session.
|
||||
* @param hdr The RTP header of the incoming packet.
|
||||
* @param hdr The RTP header of the incoming packet. The header must
|
||||
* be given with fields in network byte order.
|
||||
* @param seq_st Optional structure to receive the status of the RTP packet
|
||||
* processing.
|
||||
*/
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
struct transport_ice
|
||||
{
|
||||
pjmedia_transport base;
|
||||
pj_ice_strans *ice_st;
|
||||
pj_ice_strans *ice_st;
|
||||
|
||||
pj_time_val start_ice;
|
||||
|
||||
|
@ -408,6 +408,9 @@ PJ_DEF(pj_status_t) pjmedia_ice_start_ice(pjmedia_transport *tp,
|
|||
unsigned i, cand_cnt;
|
||||
pj_ice_sess_cand cand[PJ_ICE_MAX_CAND];
|
||||
const pjmedia_sdp_media *sdp_med;
|
||||
pj_bool_t remote_is_lite = PJ_FALSE;
|
||||
const pj_str_t STR_CANDIDATE = {"candidate", 9};
|
||||
const pj_str_t STR_ICE_LITE = {"ice-lite", 8};
|
||||
pj_str_t uname, pass;
|
||||
pj_status_t status;
|
||||
|
||||
|
@ -444,13 +447,17 @@ PJ_DEF(pj_status_t) pjmedia_ice_start_ice(pjmedia_transport *tp,
|
|||
}
|
||||
pass = attr->value;
|
||||
|
||||
/* Get all candidates */
|
||||
/* Get all candidates in the media */
|
||||
cand_cnt = 0;
|
||||
for (i=0; i<sdp_med->attr_count; ++i) {
|
||||
pjmedia_sdp_attr *attr;
|
||||
|
||||
attr = sdp_med->attr[i];
|
||||
if (pj_strcmp2(&attr->name, "candidate")!=0)
|
||||
|
||||
if (pj_strcmp(&attr->name, &STR_ICE_LITE)==0)
|
||||
remote_is_lite = PJ_TRUE;
|
||||
|
||||
if (pj_strcmp(&attr->name, &STR_CANDIDATE)!=0)
|
||||
continue;
|
||||
|
||||
status = parse_cand(pool, &attr->value, &cand[cand_cnt]);
|
||||
|
@ -463,6 +470,16 @@ PJ_DEF(pj_status_t) pjmedia_ice_start_ice(pjmedia_transport *tp,
|
|||
/* Mark start time */
|
||||
pj_gettimeofday(&tp_ice->start_ice);
|
||||
|
||||
/* If our role was controlled but it turns out that remote is
|
||||
* a lite implementation, change our role to controlling.
|
||||
*/
|
||||
if (remote_is_lite &&
|
||||
tp_ice->ice_st->ice->role == PJ_ICE_SESS_ROLE_CONTROLLED)
|
||||
{
|
||||
pj_ice_sess_change_role(tp_ice->ice_st->ice,
|
||||
PJ_ICE_SESS_ROLE_CONTROLLING);
|
||||
}
|
||||
|
||||
/* Start ICE */
|
||||
return pj_ice_strans_start_ice(tp_ice->ice_st, &uname, &pass, cand_cnt, cand);
|
||||
}
|
||||
|
@ -552,8 +569,8 @@ static pj_status_t tp_send_rtp(pjmedia_transport *tp,
|
|||
{
|
||||
struct transport_ice *tp_ice = (struct transport_ice*)tp;
|
||||
return pj_ice_strans_sendto(tp_ice->ice_st, 1,
|
||||
pkt, size, &tp_ice->remote_rtp,
|
||||
sizeof(pj_sockaddr_in));
|
||||
pkt, size, &tp_ice->remote_rtp,
|
||||
sizeof(pj_sockaddr_in));
|
||||
}
|
||||
|
||||
|
||||
|
@ -564,8 +581,8 @@ static pj_status_t tp_send_rtcp(pjmedia_transport *tp,
|
|||
struct transport_ice *tp_ice = (struct transport_ice*)tp;
|
||||
if (tp_ice->ice_st->comp_cnt > 1) {
|
||||
return pj_ice_strans_sendto(tp_ice->ice_st, 2,
|
||||
pkt, size, &tp_ice->remote_rtp,
|
||||
sizeof(pj_sockaddr_in));
|
||||
pkt, size, &tp_ice->remote_rtp,
|
||||
sizeof(pj_sockaddr_in));
|
||||
} else {
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
|
@ -549,6 +550,21 @@ PJ_DECL(pj_status_t) pj_ice_sess_create(pj_stun_config *stun_cfg,
|
|||
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
|
||||
|
|
|
@ -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. */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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,13 +534,32 @@ 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;
|
||||
|
||||
} 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.
|
||||
* STUN error code.
|
||||
*/
|
||||
pj_uint16_t zero;
|
||||
|
||||
/**
|
||||
* Error class (1-6).
|
||||
*/
|
||||
pj_uint8_t err_class;
|
||||
|
||||
/**
|
||||
* Error number is the error number modulo 100.
|
||||
*/
|
||||
pj_uint8_t number;
|
||||
int err_code;
|
||||
|
||||
/**
|
||||
* The reason phrase.
|
||||
|
@ -1348,6 +1358,37 @@ PJ_DECL(pj_status_t) pj_stun_msg_add_uint_attr(pj_pool_t *pool,
|
|||
pj_uint32_t value);
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
pj_status_t status;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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 = ATTR_LEN;
|
||||
*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 = 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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue