summaryrefslogtreecommitdiff
path: root/pjnath
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-04-02 11:30:14 +0000
committerBenny Prijono <bennylp@teluu.com>2007-04-02 11:30:14 +0000
commit1d1908a032b3d078210ca41d3d1c17d1bf90cfdd (patch)
tree910663daf7996504da5e9c140f6c3ed699c4ae8e /pjnath
parent20ce55304f7f4d40ecde7101e7dd06e7473719cf (diff)
ICE: work in progress
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1126 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjnath')
-rw-r--r--pjnath/include/pjnath/config.h15
-rw-r--r--pjnath/include/pjnath/ice_session.h41
-rw-r--r--pjnath/include/pjnath/stun_auth.h2
-rw-r--r--pjnath/include/pjnath/stun_msg.h4
-rw-r--r--pjnath/include/pjnath/types.h19
-rw-r--r--pjnath/src/pjnath/errno.c28
-rw-r--r--pjnath/src/pjnath/ice_session.c201
-rw-r--r--pjnath/src/pjnath/ice_strans.c33
-rw-r--r--pjnath/src/pjnath/stun_auth.c6
-rw-r--r--pjnath/src/pjnath/stun_msg.c17
-rw-r--r--pjnath/src/pjnath/stun_msg_dump.c7
-rw-r--r--pjnath/src/pjnath/stun_session.c18
-rw-r--r--pjnath/src/pjnath/stun_transaction.c14
13 files changed, 264 insertions, 141 deletions
diff --git a/pjnath/include/pjnath/config.h b/pjnath/include/pjnath/config.h
index 3bc5afaf..dec268f8 100644
--- a/pjnath/include/pjnath/config.h
+++ b/pjnath/include/pjnath/config.h
@@ -31,6 +31,21 @@
* @{
*/
+
+/* **************************************************************************
+ * GENERAL
+ */
+
+/**
+ * The log level for PJNATH error display.
+ *
+ * default 1
+ */
+#ifndef PJNATH_ERROR_LEVEL
+# define PJNATH_ERROR_LEVEL 1
+#endif
+
+
/* **************************************************************************
* STUN CLIENT CONFIGURATION
*/
diff --git a/pjnath/include/pjnath/ice_session.h b/pjnath/include/pjnath/ice_session.h
index 929a4e82..36ad1b27 100644
--- a/pjnath/include/pjnath/ice_session.h
+++ b/pjnath/include/pjnath/ice_session.h
@@ -97,18 +97,6 @@ typedef enum pj_ice_cand_type
} pj_ice_cand_type;
-/**
- * This enumeration describes the default preference for the ICE
- * candidate types as described by ICE standard.
- */
-enum pj_ice_type_pref
-{
- PJ_ICE_HOST_PREF = 126, /**< Preference value for host. */
- PJ_ICE_SRFLX_PREF = 100, /**< Preference value for SRFLX. */
- PJ_ICE_PRFLX_PREF = 110, /**< Preference value for PRFLX */
- PJ_ICE_RELAYED_PREF = 0 /**< Preference value for relay */
-};
-
/** Forward declaration for pj_ice_sess */
typedef struct pj_ice_sess pj_ice_sess;
@@ -273,7 +261,7 @@ struct pj_ice_sess_check
/**
* Check priority.
*/
- pj_uint64_t prio;
+ pj_timestamp prio;
/**
* Connectivity check state.
@@ -445,6 +433,7 @@ struct pj_ice_sess
pj_mutex_t *mutex; /**< Mutex. */
pj_ice_sess_role role; /**< ICE role. */
pj_timestamp tie_breaker; /**< Tie breaker value */
+ pj_uint8_t *prefs; /**< Type preference. */
pj_bool_t is_complete; /**< Complete? */
pj_status_t ice_status; /**< Error status. */
pj_ice_sess_cb cb; /**< Callback. */
@@ -566,6 +555,28 @@ PJ_DECL(pj_status_t) pj_ice_sess_change_role(pj_ice_sess *ice,
/**
+ * Assign a custom preference values for ICE candidate types. By assigning
+ * custom preference value, application can control the order of candidates
+ * to be checked first. The default preference settings is to use 126 for
+ * host candidates, 100 for server reflexive candidates, 110 for peer
+ * reflexive candidates, an 0 for relayed candidates.
+ *
+ * Note that this function must be called before any candidates are added
+ * to the ICE session.
+ *
+ * @param ice The ICE session.
+ * @param prefs Array of candidate preference value. The values are
+ * put in the array indexed by the candidate type as
+ * specified in pj_ice_cand_type.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_ice_sess_set_prefs(pj_ice_sess *ice,
+ const pj_uint8_t prefs[4]);
+
+
+
+/**
* 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.
@@ -595,6 +606,9 @@ PJ_DECL(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
int addr_len,
unsigned *p_cand_id);
+#if 0
+/* Temporarily disabled to reduce size, since we don't need this yet */
+
/**
* Find default candidate for the specified component ID, using this
* rule:
@@ -612,6 +626,7 @@ PJ_DECL(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
PJ_DECL(pj_status_t) pj_ice_sess_find_default_cand(pj_ice_sess *ice,
unsigned comp_id,
int *p_cand_id);
+#endif
/**
* Pair the local and remote candidates to create check list. Application
diff --git a/pjnath/include/pjnath/stun_auth.h b/pjnath/include/pjnath/stun_auth.h
index 6914036d..539c8867 100644
--- a/pjnath/include/pjnath/stun_auth.h
+++ b/pjnath/include/pjnath/stun_auth.h
@@ -225,6 +225,8 @@ typedef struct pj_stun_auth_cred
* in the message can be accepted. If this callback returns
* PJ_FALSE, 438 (Stale Nonce) response will be created.
*
+ * This callback is optional.
+ *
* @param msg The STUN message where the nonce was received.
* @param user_data The user data as specified in the credential.
* @param realm The realm as specified in the message.
diff --git a/pjnath/include/pjnath/stun_msg.h b/pjnath/include/pjnath/stun_msg.h
index 6c716a0c..f1544de3 100644
--- a/pjnath/include/pjnath/stun_msg.h
+++ b/pjnath/include/pjnath/stun_msg.h
@@ -1228,10 +1228,14 @@ PJ_DECL(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
*
* @return The message string output.
*/
+#if PJ_LOG_MAX_LEVEL > 0
PJ_DECL(char*) pj_stun_msg_dump(const pj_stun_msg *msg,
char *buffer,
unsigned length,
unsigned *printed_len);
+#else
+# define pj_stun_msg_dump(msg, buf, length, printed_len) ""
+#endif
/**
diff --git a/pjnath/include/pjnath/types.h b/pjnath/include/pjnath/types.h
index 72c326af..10544d22 100644
--- a/pjnath/include/pjnath/types.h
+++ b/pjnath/include/pjnath/types.h
@@ -37,11 +37,27 @@ PJ_BEGIN_DECL
/**
* Initialize pjnath library.
*
- * @return Initialization status.
+ * @return Initialization status.
*/
PJ_DECL(pj_status_t) pjnath_init(void);
+/**
+ * Display error to the log.
+ *
+ * @param sender The sender name.
+ * @param title Title message.
+ * @param status The error status.
+ */
+#if PJNATH_ERROR_LEVEL <= PJ_LOG_MAX_LEVEL
+PJ_DECL(void) pjnath_perror(const char *sender, const char *title,
+ pj_status_t status);
+#else
+# define pjnath_perror(sender, title, status)
+#endif
+
+
+
PJ_END_DECL
/**
@@ -147,6 +163,7 @@ PJ_END_DECL
* for different types of application, including but not limited to
* the usage of ICE in SIP/SDP offer/answer.
*
+ *
* \subsection PJNATH_ICE_ARCH ICE Library Organization
*
* \image html ice-arch.jpg "ICE Architecture"
diff --git a/pjnath/src/pjnath/errno.c b/pjnath/src/pjnath/errno.c
index 7ac88922..ed1f658f 100644
--- a/pjnath/src/pjnath/errno.c
+++ b/pjnath/src/pjnath/errno.c
@@ -18,6 +18,7 @@
*/
#include <pjnath/errno.h>
#include <pjnath/stun_msg.h>
+#include <pj/log.h>
#include <pj/string.h>
@@ -165,3 +166,30 @@ PJ_DEF(pj_status_t) pjnath_init(void)
return status;
}
+
+#if PJNATH_ERROR_LEVEL <= PJ_LOG_MAX_LEVEL
+
+PJ_DEF(void) pjnath_perror(const char *sender, const char *title,
+ pj_status_t status)
+{
+ char errmsg[PJ_ERR_MSG_SIZE];
+
+ pj_strerror(status, errmsg, sizeof(errmsg));
+
+#if PJNATH_ERROR_LEVEL==1
+ PJ_LOG(1,(sender, "%s: %s", title, errmsg));
+#elif PJNATH_ERROR_LEVEL==2
+ PJ_LOG(2,(sender, "%s: %s", title, errmsg));
+#elif PJNATH_ERROR_LEVEL==3
+ PJ_LOG(3,(sender, "%s: %s", title, errmsg));
+#elif PJNATH_ERROR_LEVEL==4
+ PJ_LOG(4,(sender, "%s: %s", title, errmsg));
+#elif PJNATH_ERROR_LEVEL==5
+ PJ_LOG(5,(sender, "%s: %s", title, errmsg));
+#else
+# error Invalid PJNATH_ERROR_LEVEL value
+#endif
+}
+
+#endif /* PJNATH_ERROR_LEVEL <= PJ_LOG_MAX_LEVEL */
+
diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c
index 09617965..50c593bd 100644
--- a/pjnath/src/pjnath/ice_session.c
+++ b/pjnath/src/pjnath/ice_session.c
@@ -40,6 +40,7 @@ static const char *cand_type_names[] =
};
/* String names for pj_ice_sess_check_state */
+#if PJ_LOG_MAX_LEVEL >= 4
static const char *check_state_name[] =
{
"Frozen",
@@ -55,6 +56,7 @@ static const char *clist_state_name[] =
"Running",
"Completed"
};
+#endif /* PJ_LOG_MAX_LEVEL >= 4 */
static const char *role_names[] =
{
@@ -62,6 +64,15 @@ static const char *role_names[] =
"Controlling"
};
+/* Default ICE session preferences, according to draft-ice */
+static pj_uint8_t cand_type_prefs[4] =
+{
+ 126, /**< PJ_ICE_HOST_PREF */
+ 100, /**< PJ_ICE_SRFLX_PREF. */
+ 110, /**< PJ_ICE_PRFLX_PREF */
+ 0 /**< PJ_ICE_RELAYED_PREF */
+};
+
#define CHECK_NAME_LEN 128
#define LOG4(expr) PJ_LOG(4,expr)
#define LOG5(expr) PJ_LOG(4,expr)
@@ -71,15 +82,14 @@ static const char *role_names[] =
typedef struct stun_data
{
- pj_ice_sess *ice;
- unsigned lcand_id;
+ pj_ice_sess *ice;
pj_ice_sess_cand *lcand;
} stun_data;
typedef struct timer_data
{
- pj_ice_sess *ice;
- pj_ice_sess_checklist *clist;
+ pj_ice_sess *ice;
+ pj_ice_sess_checklist *clist;
} timer_data;
@@ -131,11 +141,6 @@ static pj_status_t stun_auth_get_password(const pj_stun_msg *msg,
pj_pool_t *pool,
int *data_type,
pj_str_t *data);
-static pj_bool_t stun_auth_verify_nonce(const pj_stun_msg *msg,
- void *user_data,
- const pj_str_t *realm,
- const pj_str_t *username,
- const pj_str_t *nonce);
PJ_DEF(const char*) pj_ice_get_cand_type_name(pj_ice_cand_type type)
@@ -188,8 +193,6 @@ PJ_DEF(pj_status_t) pj_ice_sess_create(pj_stun_config *stun_cfg,
{
pj_pool_t *pool;
pj_ice_sess *ice;
- char tmp[64];
- pj_str_t s;
unsigned i;
pj_status_t status;
@@ -204,6 +207,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_create(pj_stun_config *stun_cfg,
ice->role = role;
ice->tie_breaker.u32.hi = pj_rand();
ice->tie_breaker.u32.lo = pj_rand();
+ ice->prefs = cand_type_prefs;
pj_ansi_snprintf(ice->obj_name, sizeof(ice->obj_name),
name, ice);
@@ -226,18 +230,18 @@ PJ_DEF(pj_status_t) pj_ice_sess_create(pj_stun_config *stun_cfg,
}
if (local_ufrag == NULL) {
- pj_ansi_snprintf(tmp, sizeof(tmp), "%x%x", pj_rand(), pj_rand());
- s = pj_str(tmp);
- local_ufrag = &s;
+ ice->rx_ufrag.ptr = pj_pool_alloc(ice->pool, 16);
+ pj_create_random_string(ice->rx_ufrag.ptr, 16);
+ } else {
+ pj_strdup(ice->pool, &ice->rx_ufrag, local_ufrag);
}
- pj_strdup(ice->pool, &ice->rx_ufrag, local_ufrag);
if (local_passwd == NULL) {
- pj_ansi_snprintf(tmp, sizeof(tmp), "%x%x", pj_rand(), pj_rand());
- s = pj_str(tmp);
- local_passwd = &s;
+ ice->rx_pass.ptr = pj_pool_alloc(ice->pool, 16);
+ pj_create_random_string(ice->rx_pass.ptr, 16);
+ } else {
+ pj_strdup(ice->pool, &ice->rx_pass, local_passwd);
}
- pj_strdup(ice->pool, &ice->rx_pass, local_passwd);
/* Done */
@@ -316,6 +320,20 @@ PJ_DEF(pj_status_t) pj_ice_sess_change_role(pj_ice_sess *ice,
}
+/*
+ * Change type preference
+ */
+PJ_DEF(pj_status_t) pj_ice_sess_set_prefs(pj_ice_sess *ice,
+ const pj_uint8_t prefs[4])
+{
+ PJ_ASSERT_RETURN(ice && prefs, PJ_EINVAL);
+ ice->prefs = pj_pool_calloc(ice->pool, PJ_ARRAY_SIZE(prefs),
+ sizeof(pj_uint8_t));
+ pj_memcpy(ice->prefs, prefs, sizeof(prefs));
+ return PJ_SUCCESS;
+}
+
+
/* Find component by ID */
static pj_ice_sess_comp *find_comp(const pj_ice_sess *ice, unsigned comp_id)
{
@@ -421,35 +439,12 @@ static pj_status_t stun_auth_get_password(const pj_stun_msg *msg,
}
-static pj_bool_t stun_auth_verify_nonce(const pj_stun_msg *msg,
- void *user_data,
- const pj_str_t *realm,
- const pj_str_t *username,
- const pj_str_t *nonce)
-{
- /* We don't use NONCE */
- PJ_UNUSED_ARG(msg);
- PJ_UNUSED_ARG(user_data);
- PJ_UNUSED_ARG(realm);
- PJ_UNUSED_ARG(username);
- PJ_UNUSED_ARG(nonce);
- return PJ_TRUE;
-}
-
-
-static pj_uint32_t CALC_CAND_PRIO(pj_ice_cand_type type,
+static pj_uint32_t CALC_CAND_PRIO(pj_ice_sess *ice,
+ pj_ice_cand_type type,
pj_uint32_t local_pref,
pj_uint32_t comp_id)
{
- pj_uint32_t type_pref[] =
- {
- PJ_ICE_HOST_PREF,
- PJ_ICE_SRFLX_PREF,
- PJ_ICE_PRFLX_PREF,
- PJ_ICE_RELAYED_PREF
- };
-
- return ((type_pref[type] & 0xFF) << 24) +
+ return ((ice->prefs[type] & 0xFF) << 24) +
((local_pref & 0xFFFF) << 8) +
(((256 - comp_id) & 0xFF) << 0);
}
@@ -492,7 +487,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
lcand->comp_id = comp_id;
lcand->type = type;
pj_strdup(ice->pool, &lcand->foundation, foundation);
- lcand->prio = CALC_CAND_PRIO(type, local_pref, lcand->comp_id);
+ lcand->prio = CALC_CAND_PRIO(ice, type, local_pref, lcand->comp_id);
pj_memcpy(&lcand->addr, addr, addr_len);
pj_memcpy(&lcand->base_addr, base_addr, addr_len);
if (rel_addr)
@@ -520,7 +515,6 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
/* Associate data with this STUN session */
sd = PJ_POOL_ZALLOC_T(ice->pool, struct stun_data);
sd->ice = ice;
- sd->lcand_id = GET_LCAND_ID(lcand);
sd->lcand = lcand;
pj_stun_session_set_user_data(lcand->stun_sess, sd);
@@ -530,7 +524,6 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
auth_cred.data.dyn_cred.get_auth = &stun_auth_get_auth;
auth_cred.data.dyn_cred.get_cred = &stun_auth_get_cred;
auth_cred.data.dyn_cred.get_password = &stun_auth_get_password;
- auth_cred.data.dyn_cred.verify_nonce = &stun_auth_verify_nonce;
auth_cred.data.dyn_cred.user_data = lcand->stun_sess;
pj_stun_session_set_credential(lcand->stun_sess, &auth_cred);
@@ -562,6 +555,7 @@ on_error:
/* Find default candidate ID for the component */
+#if 0
PJ_DEF(pj_status_t) pj_ice_sess_find_default_cand(pj_ice_sess *ice,
unsigned comp_id,
int *cand_id)
@@ -629,6 +623,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_find_default_cand(pj_ice_sess *ice,
pj_assert(!"Should have a candidate by now");
return PJ_EBUG;
}
+#endif /* if 0 */
#ifndef MIN
@@ -639,11 +634,16 @@ PJ_DEF(pj_status_t) pj_ice_sess_find_default_cand(pj_ice_sess *ice,
# define MAX(a,b) (a > b ? a : b)
#endif
-static pj_uint64_t CALC_CHECK_PRIO(const pj_ice_sess *ice,
- const pj_ice_sess_cand *lcand,
- const pj_ice_sess_cand *rcand)
+static pj_timestamp CALC_CHECK_PRIO(const pj_ice_sess *ice,
+ const pj_ice_sess_cand *lcand,
+ const pj_ice_sess_cand *rcand)
{
pj_uint32_t O, A;
+ pj_timestamp prio;
+
+ /* Original formula:
+ * pair priority = 2^32*MIN(O,A) + 2*MAX(O,A) + (O>A?1:0)
+ */
if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING) {
O = lcand->prio;
@@ -653,10 +653,26 @@ static pj_uint64_t CALC_CHECK_PRIO(const pj_ice_sess *ice,
A = lcand->prio;
}
+ /*
return ((pj_uint64_t)1 << 32) * MIN(O, A) +
(pj_uint64_t)2 * MAX(O, A) + (O>A ? 1 : 0);
+ */
+
+ prio.u32.hi = MIN(O,A);
+ prio.u32.lo = (MAX(O, A) << 1) + (O>A ? 1 : 0);
+
+ return prio;
}
+
+PJ_INLINE(int) CMP_CHECK_PRIO(const pj_ice_sess_check *c1,
+ const pj_ice_sess_check *c2)
+{
+ return pj_cmp_timestamp(&c1->prio, &c2->prio);
+}
+
+
+#if PJ_LOG_MAX_LEVEL >= 4
static const char *dump_check(char *buffer, unsigned bufsize,
const pj_ice_sess_checklist *clist,
const pj_ice_sess_check *check)
@@ -690,7 +706,6 @@ static const char *dump_check(char *buffer, unsigned bufsize,
return buffer;
}
-#if PJ_LOG_MAX_LEVEL >= 4
static void dump_checklist(const char *title, const pj_ice_sess *ice,
const pj_ice_sess_checklist *clist)
{
@@ -746,7 +761,7 @@ static void sort_checklist(pj_ice_sess_checklist *clist)
for (i=0; i<clist->count-1; ++i) {
unsigned j, highest = i;
for (j=i+1; j<clist->count; ++j) {
- if (clist->checks[j].prio > clist->checks[highest].prio) {
+ if (CMP_CHECK_PRIO(&clist->checks[j], &clist->checks[highest]) > 0) {
highest = j;
}
}
@@ -827,15 +842,15 @@ static void prune_checklist(pj_ice_sess *ice, pj_ice_sess_checklist *clist)
else
ljaddr = &ljcand->addr;
- if (sockaddr_cmp(liaddr, ljaddr) == SOCKADDR_EQUAL &&
- sockaddr_cmp(&ricand->addr, &rjcand->addr) == SOCKADDR_EQUAL)
+ if (ricand == rjcand &&
+ sockaddr_cmp(liaddr, ljaddr) == SOCKADDR_EQUAL)
{
/* Found duplicate, remove it */
char buf[CHECK_NAME_LEN];
LOG5((ice->obj_name, "Check %s pruned",
- dump_check(buf, sizeof(buf), &ice->clist,
- &clist->checks[j])));
+ dump_check(buf, sizeof(buf), &ice->clist,
+ &clist->checks[j])));
pj_array_erase(clist->checks, sizeof(clist->checks[0]),
clist->count, j);
@@ -928,7 +943,7 @@ static pj_bool_t on_check_complete(pj_ice_sess *ice,
if (comp->valid_check == NULL) {
comp->valid_check = check;
} else {
- if (comp->valid_check->prio < check->prio)
+ if (CMP_CHECK_PRIO(comp->valid_check, check) < 0)
comp->valid_check = check;
}
}
@@ -1154,8 +1169,10 @@ static pj_status_t perform_check(pj_ice_sess *ice,
status = pj_stun_session_create_req(lcand->stun_sess,
PJ_STUN_BINDING_REQUEST,
&check->tdata);
- if (status != PJ_SUCCESS)
+ if (status != PJ_SUCCESS) {
+ pjnath_perror(ice->obj_name, "Error creating STUN request", status);
return status;
+ }
/* Attach data to be retrieved later when STUN request transaction
* completes and on_stun_request_complete() callback is called.
@@ -1167,7 +1184,7 @@ static pj_status_t perform_check(pj_ice_sess *ice,
check->tdata->user_data = (void*) rd;
/* Add PRIORITY */
- prio = CALC_CAND_PRIO(PJ_ICE_CAND_TYPE_PRFLX, 65535,
+ prio = CALC_CAND_PRIO(ice, PJ_ICE_CAND_TYPE_PRFLX, 65535,
lcand->comp_id);
pj_stun_msg_add_uint_attr(check->tdata->pool, check->tdata->msg,
PJ_STUN_ATTR_PRIORITY, prio);
@@ -1189,6 +1206,7 @@ static pj_status_t perform_check(pj_ice_sess *ice,
sizeof(pj_sockaddr_in), check->tdata);
if (status != PJ_SUCCESS) {
check->tdata = NULL;
+ pjnath_perror(ice->obj_name, "Error sending STUN request", status);
return status;
}
@@ -1289,38 +1307,79 @@ static void periodic_timer(pj_timer_heap_t *th,
start_periodic_check(th, te);
}
+
+/* Utility: find string in string array */
+const pj_str_t *find_str(const pj_str_t *strlist[], unsigned count,
+ const pj_str_t *str)
+{
+ unsigned i;
+ for (i=0; i<count; ++i) {
+ if (pj_strcmp(strlist[i], str)==0)
+ return strlist[i];
+ }
+ return NULL;
+}
+
/* Start ICE check */
PJ_DEF(pj_status_t) pj_ice_sess_start_check(pj_ice_sess *ice)
{
pj_ice_sess_checklist *clist;
const pj_ice_sess_cand *cand0;
- unsigned i;
+ const pj_str_t *flist[PJ_ICE_MAX_CAND];
+ unsigned i, flist_cnt = 0;
PJ_ASSERT_RETURN(ice, PJ_EINVAL);
- /* Checklist must be created */
+
+ /* Checklist must have been created */
PJ_ASSERT_RETURN(ice->clist.count > 0, PJ_EINVALIDOP);
LOG4((ice->obj_name, "Starting ICE check.."));
+ /* The agent examines the check list for the first media stream (a
+ * media stream is the first media stream when it is described by
+ * the first m-line in the SDP offer and answer). For that media
+ * stream, it:
+ *
+ * - Groups together all of the pairs with the same foundation,
+ *
+ * - For each group, sets the state of the pair with the lowest
+ * component ID to Waiting. If there is more than one such pair,
+ * the one with the highest priority is used.
+ */
+
clist = &ice->clist;
- /* Pickup the first pair and set the state to Waiting */
- clist->checks[0].state = PJ_ICE_SESS_CHECK_STATE_WAITING;
- cand0 = clist->checks[0].lcand;
+ /* Pickup the first pair for component 1. */
+ for (i=0; i<clist->count; ++i) {
+ if (clist->checks[0].lcand->comp_id == 1)
+ break;
+ }
+ if (i == clist->count) {
+ pj_assert(!"Unable to find checklist for component 1");
+ return PJNATH_EICEINCOMPID;
+ }
+
+ /* Set this check to WAITING */
+ check_set_state(ice, &clist->checks[i],
+ PJ_ICE_SESS_CHECK_STATE_WAITING, PJ_SUCCESS);
+ cand0 = clist->checks[i].lcand;
+ flist[flist_cnt++] = &clist->checks[i].lcand->foundation;
/* Find all of the other pairs in that check list with the same
* component ID, but different foundations, and sets all of their
* states to Waiting as well.
*/
- for (i=1; i<clist->count; ++i) {
+ for (++i; i<clist->count; ++i) {
const pj_ice_sess_cand *cand1;
cand1 = clist->checks[i].lcand;
- if (cand0->comp_id == cand1->comp_id &&
- pj_strcmp(&cand0->foundation, &cand1->foundation)!=0)
+ if (cand1->comp_id==cand0->comp_id &&
+ find_str(flist, flist_cnt, &cand1->foundation)==NULL)
{
- clist->checks[i].state = PJ_ICE_SESS_CHECK_STATE_WAITING;
+ check_set_state(ice, &clist->checks[i],
+ PJ_ICE_SESS_CHECK_STATE_WAITING, PJ_SUCCESS);
+ flist[flist_cnt++] = &cand1->foundation;
}
}
@@ -1341,7 +1400,9 @@ static pj_status_t on_stun_send_msg(pj_stun_session *sess,
unsigned addr_len)
{
stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess);
- return (*sd->ice->cb.on_tx_pkt)(sd->ice, sd->lcand->comp_id, sd->lcand_id,
+ pj_ice_sess *ice = sd->ice;
+ return (*sd->ice->cb.on_tx_pkt)(sd->ice, sd->lcand->comp_id,
+ GET_LCAND_ID(sd->lcand),
pkt, pkt_size,
dst_addr, addr_len);
}
diff --git a/pjnath/src/pjnath/ice_strans.c b/pjnath/src/pjnath/ice_strans.c
index 378d13a4..082d310a 100644
--- a/pjnath/src/pjnath/ice_strans.c
+++ b/pjnath/src/pjnath/ice_strans.c
@@ -65,19 +65,7 @@ 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,
- pj_status_t status)
-{
- char errmsg[PJ_ERR_MSG_SIZE];
-
- pj_strerror(status, errmsg, sizeof(errmsg));
- PJ_LOG(3,(ice_st->obj_name, "%s: %s", title, errmsg));
-}
-#else
-# define ice_st_perror(ice_st, title, status)
-#endif
-
+#define ice_st_perror(ice_st,msg,rc) pjnath_perror(ice_st->obj_name,msg,rc)
/*
* Create ICE stream transport
@@ -344,6 +332,7 @@ static pj_status_t create_component(pj_ice_strans *ice_st,
for (i=0; i<ifs_cnt; ++i) {
pj_sockaddr_in cand_addr;
pj_bool_t set_default;
+ pj_uint16_t local_pref;
/* Ignore 127.0.0.0/24 address */
if ((pj_ntohl(ifs[i].s_addr) >> 24)==127)
@@ -358,14 +347,15 @@ static pj_status_t create_component(pj_ice_strans *ice_st,
*/
if (ifs[i].s_addr == comp->local_addr.ipv4.sin_addr.s_addr) {
set_default = PJ_TRUE;
+ local_pref = 65535;
} else {
set_default = PJ_FALSE;
+ local_pref = 0;
}
status = add_cand(ice_st, comp, comp_id,
PJ_ICE_CAND_TYPE_HOST,
- (pj_uint16_t)(65535-i), &cand_addr,
- set_default);
+ local_pref, &cand_addr, set_default);
if (status != PJ_SUCCESS)
goto on_error;
}
@@ -759,6 +749,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
pj_status_t status;
unsigned i;
pj_ice_sess_cb ice_cb;
+ const pj_uint8_t srflx_prio[4] = { 100, 126, 110, 0 };
/* Check arguments */
PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
@@ -783,6 +774,18 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
/* Associate user data */
ice_st->ice->user_data = (void*)ice_st;
+ /* If default candidate for components are SRFLX one, upload a custom
+ * type priority to ICE session so that SRFLX candidates will get
+ * checked first.
+ */
+ if (ice_st->comp[0]->default_cand >= 0 &&
+ ice_st->comp[0]->cand_list[ice_st->comp[0]->default_cand].type
+ == PJ_ICE_CAND_TYPE_SRFLX)
+ {
+ pj_ice_sess_set_prefs(ice_st->ice, srflx_prio);
+ }
+
+
/* Add candidates */
for (i=0; i<ice_st->comp_cnt; ++i) {
unsigned j;
diff --git a/pjnath/src/pjnath/stun_auth.c b/pjnath/src/pjnath/stun_auth.c
index 15f226dc..3f5a77a5 100644
--- a/pjnath/src/pjnath/stun_auth.c
+++ b/pjnath/src/pjnath/stun_auth.c
@@ -269,12 +269,16 @@ PJ_DEF(pj_status_t) pj_stun_verify_credential( const pj_uint8_t *pkt,
if (anonce) {
pj_bool_t ok;
- if (cred->type == PJ_STUN_AUTH_CRED_DYNAMIC) {
+ if (cred->type == PJ_STUN_AUTH_CRED_DYNAMIC &&
+ cred->data.dyn_cred.verify_nonce != NULL)
+ {
ok=cred->data.dyn_cred.verify_nonce(msg,
cred->data.dyn_cred.user_data,
(arealm?&arealm->value:NULL),
&auser->value,
&anonce->value);
+ } else if (cred->type == PJ_STUN_AUTH_CRED_DYNAMIC) {
+ ok = PJ_TRUE;
} else {
if (nonce.slen) {
ok = !pj_strcmp(&anonce->value, &nonce);
diff --git a/pjnath/src/pjnath/stun_msg.c b/pjnath/src/pjnath/stun_msg.c
index 072a7a1b..5b54ff38 100644
--- a/pjnath/src/pjnath/stun_msg.c
+++ b/pjnath/src/pjnath/stun_msg.c
@@ -139,7 +139,7 @@ static pj_status_t encode_empty_attr(const void *a, pj_uint8_t *buf,
unsigned len, unsigned *printed);
-struct attr_desc mandatory_attr_desc[] =
+static struct attr_desc mandatory_attr_desc[] =
{
{
/* type zero */
@@ -437,13 +437,13 @@ static struct attr_desc extended_attr_desc[] =
},
{
/* PJ_STUN_ATTR_ICE_CONTROLLED, */
- "ICE-CCONTROLLED",
+ "ICE-CONTROLLED",
&decode_uint64_attr,
&encode_uint64_attr
},
{
/* PJ_STUN_ATTR_ICE_CONTROLLING, */
- "ICE-CCONTROLLING",
+ "ICE-CONTROLLING",
&decode_uint64_attr,
&encode_uint64_attr
}
@@ -1870,8 +1870,6 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
if (has_msg_int) {
/* Already has MESSAGE-INTEGRITY */
if (p_response) {
- pj_str_t e;
- e = pj_str("MESSAGE-INTEGRITY already present");
pj_stun_msg_create_response(pool, msg,
PJ_STUN_SC_BAD_REQUEST,
NULL, p_response);
@@ -1884,8 +1882,6 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
if (has_fingerprint) {
/* Already has FINGERPRINT */
if (p_response) {
- pj_str_t e;
- e = pj_str("FINGERPRINT already present");
pj_stun_msg_create_response(pool, msg,
PJ_STUN_SC_BAD_REQUEST,
NULL, p_response);
@@ -1898,8 +1894,6 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
/* Another attribute is found which is not FINGERPRINT
* after FINGERPRINT or MESSAGE-INTEGRITY */
if (p_response) {
- pj_str_t e;
- e = pj_str("Invalid attribute order");
pj_stun_msg_create_response(pool, msg,
PJ_STUN_SC_BAD_REQUEST,
NULL, p_response);
@@ -1912,12 +1906,9 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
/* Make sure we have rooms for the new attribute */
if (msg->attr_count >= PJ_STUN_MAX_ATTR) {
if (p_response) {
- pj_str_t e;
-
- e = pj_str("Too many attributes");
pj_stun_msg_create_response(pool, msg,
PJ_STUN_SC_BAD_REQUEST,
- &e, p_response);
+ NULL, p_response);
}
return PJNATH_ESTUNTOOMANYATTR;
}
diff --git a/pjnath/src/pjnath/stun_msg_dump.c b/pjnath/src/pjnath/stun_msg_dump.c
index e888e91e..0da2cc21 100644
--- a/pjnath/src/pjnath/stun_msg_dump.c
+++ b/pjnath/src/pjnath/stun_msg_dump.c
@@ -22,6 +22,9 @@
#include <pj/string.h>
+#if PJ_LOG_MAX_LEVEL > 0
+
+
#define APPLY() if (len < 1 || len >= (end-p)) \
goto on_return; \
p += len
@@ -244,7 +247,9 @@ on_return:
*printed_len = (p-buffer);
return buffer;
+#undef APPLY
}
-#undef APPLY
+#endif /* PJ_LOG_MAX_LEVEL > 0 */
+
diff --git a/pjnath/src/pjnath/stun_session.c b/pjnath/src/pjnath/stun_session.c
index 2694d5ac..5f308fcd 100644
--- a/pjnath/src/pjnath/stun_session.c
+++ b/pjnath/src/pjnath/stun_session.c
@@ -43,21 +43,7 @@ struct pj_stun_session
# define TRACE_(expr)
#endif
-#if PJ_LOG_MAX_LEVEL >= 4
-# define LOG_ERR_(sess, title, rc) stun_perror(sess, title, rc)
-static void stun_perror(pj_stun_session *sess, const char *title,
- pj_status_t status)
-{
- char errmsg[PJ_ERR_MSG_SIZE];
-
- pj_strerror(status, errmsg, sizeof(errmsg));
-
- PJ_LOG(4,(SNAME(sess), "%s: %s", title, errmsg));
-}
-
-#else
-# define LOG_ERR_(sess, title, rc)
-#endif
+#define LOG_ERR_(sess,title,rc) pjnath_perror(sess->pool->obj_name,title,rc)
#define TDATA_POOL_SIZE 1024
#define TDATA_POOL_INC 1024
@@ -779,7 +765,7 @@ static pj_status_t on_incoming_response(pj_stun_session *sess,
/* Lookup pending client transaction */
tdata = tsx_lookup(sess, msg);
if (tdata == NULL) {
- PJ_LOG(4,(SNAME(sess),
+ PJ_LOG(5,(SNAME(sess),
"Transaction not found, response silently discarded"));
return PJ_SUCCESS;
}
diff --git a/pjnath/src/pjnath/stun_transaction.c b/pjnath/src/pjnath/stun_transaction.c
index 69829919..5d6f80f6 100644
--- a/pjnath/src/pjnath/stun_transaction.c
+++ b/pjnath/src/pjnath/stun_transaction.c
@@ -50,15 +50,7 @@ struct pj_stun_client_tsx
static void retransmit_timer_callback(pj_timer_heap_t *timer_heap,
pj_timer_entry *timer);
-static void stun_perror(pj_stun_client_tsx *tsx, const char *title,
- pj_status_t status)
-{
- char errmsg[PJ_ERR_MSG_SIZE];
-
- pj_strerror(status, errmsg, sizeof(errmsg));
- PJ_LOG(4,(tsx->obj_name, "%s: %s", title, errmsg));
-}
-
+#define stun_perror(tsx,msg,rc) pjnath_perror(tsx->obj_name, msg, rc)
/*
* Create a STUN client transaction.
@@ -84,7 +76,7 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_create(pj_stun_config *cfg,
*p_tsx = tsx;
- PJ_LOG(4,(tsx->obj_name, "STUN client transaction created"));
+ PJ_LOG(5,(tsx->obj_name, "STUN client transaction created"));
return PJ_SUCCESS;
}
@@ -191,7 +183,7 @@ static pj_status_t tsx_transmit_msg(pj_stun_client_tsx *tsx)
tsx->transmit_count++;
- PJ_LOG(4,(tsx->obj_name, "STUN sending message (transmit count=%d)",
+ PJ_LOG(5,(tsx->obj_name, "STUN sending message (transmit count=%d)",
tsx->transmit_count));
return status;
}