Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
libnice
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
libnice
Commits
eb7c964d
Commit
eb7c964d
authored
Oct 16, 2008
by
Youness Alaoui
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add full support for refreshs as well as retransmissions of those turn refresh requests
parent
b1957e7e
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
265 additions
and
3 deletions
+265
-3
agent/agent-priv.h
agent/agent-priv.h
+1
-0
agent/agent.c
agent/agent.c
+5
-0
agent/conncheck.c
agent/conncheck.c
+259
-3
No files found.
agent/agent-priv.h
View file @
eb7c964d
...
@@ -88,6 +88,7 @@ struct _NiceAgent
...
@@ -88,6 +88,7 @@ struct _NiceAgent
GSource
*
discovery_timer_source
;
/**< source of discovery timer */
GSource
*
discovery_timer_source
;
/**< source of discovery timer */
GSource
*
conncheck_timer_source
;
/**< source of conncheck timer */
GSource
*
conncheck_timer_source
;
/**< source of conncheck timer */
GSource
*
keepalive_timer_source
;
/**< source of keepalive timer */
GSource
*
keepalive_timer_source
;
/**< source of keepalive timer */
GSList
*
refresh_list
;
/**< list of CandidateRefresh items */
guint64
tie_breaker
;
/**< tie breaker (ICE sect 5.2
guint64
tie_breaker
;
/**< tie breaker (ICE sect 5.2
"Determining Role" ID-19) */
"Determining Role" ID-19) */
GStaticRecMutex
mutex
;
/* Mutex used for thread-safe lib */
GStaticRecMutex
mutex
;
/* Mutex used for thread-safe lib */
...
...
agent/agent.c
View file @
eb7c964d
...
@@ -371,6 +371,8 @@ nice_agent_init (NiceAgent *agent)
...
@@ -371,6 +371,8 @@ nice_agent_init (NiceAgent *agent)
agent
->
discovery_timer_source
=
NULL
;
agent
->
discovery_timer_source
=
NULL
;
agent
->
conncheck_timer_source
=
NULL
;
agent
->
conncheck_timer_source
=
NULL
;
agent
->
keepalive_timer_source
=
NULL
;
agent
->
keepalive_timer_source
=
NULL
;
agent
->
refresh_list
=
NULL
;
agent
->
compatibility
=
NICE_COMPATIBILITY_DRAFT19
;
agent
->
compatibility
=
NICE_COMPATIBILITY_DRAFT19
;
stun_agent_init
(
&
agent
->
stun_agent
,
STUN_ALL_KNOWN_ATTRIBUTES
,
stun_agent_init
(
&
agent
->
stun_agent
,
STUN_ALL_KNOWN_ATTRIBUTES
,
...
@@ -935,6 +937,7 @@ nice_agent_remove_stream (
...
@@ -935,6 +937,7 @@ nice_agent_remove_stream (
/* note: remove items with matching stream_ids from both lists */
/* note: remove items with matching stream_ids from both lists */
conn_check_prune_stream
(
agent
,
stream
);
conn_check_prune_stream
(
agent
,
stream
);
discovery_prune_stream
(
agent
,
stream_id
);
discovery_prune_stream
(
agent
,
stream_id
);
refresh_prune_stream
(
agent
,
stream_id
);
/* remove the stream itself */
/* remove the stream itself */
for
(
i
=
stream
->
components
;
i
;
i
=
i
->
next
)
{
for
(
i
=
stream
->
components
;
i
;
i
=
i
->
next
)
{
...
@@ -1761,6 +1764,8 @@ nice_agent_dispose (GObject *object)
...
@@ -1761,6 +1764,8 @@ nice_agent_dispose (GObject *object)
/* step: free resources for the binding discovery timers */
/* step: free resources for the binding discovery timers */
discovery_free
(
agent
);
discovery_free
(
agent
);
g_assert
(
agent
->
discovery_list
==
NULL
);
g_assert
(
agent
->
discovery_list
==
NULL
);
refresh_free
(
agent
);
g_assert
(
agent
->
refresh_list
==
NULL
);
/* step: free resources for the connectivity check timers */
/* step: free resources for the connectivity check timers */
conn_check_free
(
agent
);
conn_check_free
(
agent
);
...
...
agent/conncheck.c
View file @
eb7c964d
...
@@ -515,6 +515,117 @@ static gboolean priv_conn_keepalive_tick (gpointer pointer)
...
@@ -515,6 +515,117 @@ static gboolean priv_conn_keepalive_tick (gpointer pointer)
return
ret
;
return
ret
;
}
}
static
gboolean
priv_turn_allocate_refresh_retransmissions_tick
(
gpointer
pointer
)
{
CandidateRefresh
*
cand
=
(
CandidateRefresh
*
)
pointer
;
guint
timeout
;
g_static_rec_mutex_lock
(
&
cand
->
agent
->
mutex
);
g_source_destroy
(
cand
->
tick_source
);
g_source_unref
(
cand
->
tick_source
);
cand
->
tick_source
=
NULL
;
timeout
=
stun_timer_refresh
(
&
cand
->
timer
);
switch
(
timeout
)
{
case
-
1
:
/* Time out */
refresh_cancel
(
cand
);
break
;
case
0
:
/* Retransmit */
nice_socket_send
(
cand
->
nicesock
,
&
cand
->
server
,
stun_message_length
(
&
cand
->
stun_message
),
(
gchar
*
)
cand
->
stun_buffer
);
timeout
=
stun_timer_remainder
(
&
cand
->
timer
);
cand
->
tick_source
=
agent_timeout_add_with_context
(
cand
->
agent
,
timeout
,
priv_turn_allocate_refresh_retransmissions_tick
,
cand
);
break
;
default:
cand
->
tick_source
=
agent_timeout_add_with_context
(
cand
->
agent
,
timeout
,
priv_turn_allocate_refresh_retransmissions_tick
,
cand
);
break
;
}
g_static_rec_mutex_unlock
(
&
cand
->
agent
->
mutex
);
return
FALSE
;
}
static
void
priv_turn_allocate_refresh_tick_unlocked
(
CandidateRefresh
*
cand
)
{
uint8_t
*
username
;
size_t
username_len
;
uint8_t
*
password
;
size_t
password_len
;
size_t
buffer_len
=
0
;
username
=
(
uint8_t
*
)
cand
->
component
->
turn_username
;
username_len
=
(
size_t
)
strlen
(
cand
->
component
->
turn_username
);
password
=
(
uint8_t
*
)
cand
->
component
->
turn_password
;
password_len
=
(
size_t
)
strlen
(
cand
->
component
->
turn_password
);
if
(
cand
->
agent
->
compatibility
==
NICE_COMPATIBILITY_MSN
)
{
username
=
g_base64_decode
((
gchar
*
)
username
,
&
username_len
);
password
=
g_base64_decode
((
gchar
*
)
password
,
&
password_len
);
}
buffer_len
=
stun_usage_turn_create_refresh
(
&
cand
->
turn_agent
,
&
cand
->
stun_message
,
cand
->
stun_buffer
,
sizeof
(
cand
->
stun_buffer
),
cand
->
stun_resp_msg
.
buffer
==
NULL
?
NULL
:
&
cand
->
stun_resp_msg
,
-
1
,
username
,
username_len
,
password
,
password_len
,
priv_agent_to_turn_compatibility
(
cand
->
agent
));
if
(
cand
->
agent
->
compatibility
==
NICE_COMPATIBILITY_MSN
)
{
g_free
(
cand
->
msn_turn_username
);
g_free
(
cand
->
msn_turn_password
);
cand
->
msn_turn_username
=
username
;
cand
->
msn_turn_password
=
password
;
}
nice_debug
(
"Agent %p : Sending allocate Refresh %d"
,
agent
,
buffer_len
);
if
(
buffer_len
>
0
)
{
stun_timer_start
(
&
cand
->
timer
);
/* send the refresh */
nice_socket_send
(
cand
->
nicesock
,
&
cand
->
server
,
buffer_len
,
(
gchar
*
)
cand
->
stun_buffer
);
if
(
cand
->
tick_source
!=
NULL
)
{
g_source_destroy
(
cand
->
tick_source
);
g_source_unref
(
cand
->
tick_source
);
cand
->
tick_source
=
NULL
;
}
cand
->
tick_source
=
agent_timeout_add_with_context
(
cand
->
agent
,
stun_timer_remainder
(
&
cand
->
timer
),
priv_turn_allocate_refresh_retransmissions_tick
,
cand
);
}
}
/**
* Timer callback that handles refreshing TURN allocations
*
* This function is designed for the g_timeout_add() interface.
*
* @return will return FALSE when no more pending timers.
*/
static
gboolean
priv_turn_allocate_refresh_tick
(
gpointer
pointer
)
{
CandidateRefresh
*
cand
=
(
CandidateRefresh
*
)
pointer
;
g_static_rec_mutex_lock
(
&
cand
->
agent
->
mutex
);
priv_turn_allocate_refresh_tick_unlocked
(
cand
);
g_static_rec_mutex_unlock
(
&
cand
->
agent
->
mutex
);
return
FALSE
;
}
/**
/**
* Initiates the next pending connectivity check.
* Initiates the next pending connectivity check.
*
*
...
@@ -1729,6 +1840,43 @@ static gboolean priv_map_reply_to_discovery_request (NiceAgent *agent, StunMessa
...
@@ -1729,6 +1840,43 @@ static gboolean priv_map_reply_to_discovery_request (NiceAgent *agent, StunMessa
}
}
static
CandidateRefresh
*
priv_add_new_turn_refresh
(
CandidateDiscovery
*
cdisco
,
NiceCandidate
*
relay_cand
,
guint
lifetime
)
{
CandidateRefresh
*
cand
;
NiceAgent
*
agent
=
cdisco
->
agent
;
GSList
*
modified_list
;
cand
=
g_slice_new0
(
CandidateRefresh
);
if
(
cand
)
{
modified_list
=
g_slist_append
(
agent
->
refresh_list
,
cand
);
if
(
modified_list
)
{
cand
->
nicesock
=
cdisco
->
nicesock
;
cand
->
relay_socket
=
relay_cand
->
sockptr
;
cand
->
server
=
cdisco
->
server
;
cand
->
stream
=
cdisco
->
stream
;
cand
->
component
=
cdisco
->
component
;
cand
->
agent
=
cdisco
->
agent
;
memcpy
(
&
cand
->
turn_agent
,
&
cdisco
->
turn_agent
,
sizeof
(
StunAgent
));
nice_debug
(
"Agent %p : Adding new refresh candidate %p with timeout %d"
,
agent
,
cand
,
(
lifetime
-
60
)
*
1000
);
agent
->
refresh_list
=
modified_list
;
/* step: also start the keepalive timer */
/* refresh should be sent 1 minute before it expires */
cand
->
timer_source
=
agent_timeout_add_with_context
(
agent
,
(
lifetime
-
60
)
*
1000
,
priv_turn_allocate_refresh_tick
,
cand
);
nice_debug
(
"timer source is : %d"
,
cand
->
timer_source
);
}
}
return
cand
;
}
/**
/**
* Tries to match STUN reply in 'buf' to an existing STUN discovery
* Tries to match STUN reply in 'buf' to an existing STUN discovery
* transaction. If found, a reply is sent.
* transaction. If found, a reply is sent.
...
@@ -1776,6 +1924,7 @@ static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *
...
@@ -1776,6 +1924,7 @@ static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *
res
==
STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS
)
{
res
==
STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS
)
{
/* case: succesful allocate, create a new local candidate */
/* case: succesful allocate, create a new local candidate */
NiceAddress
niceaddr
;
NiceAddress
niceaddr
;
NiceCandidate
*
relay_cand
;
/* We also received our mapped address */
/* We also received our mapped address */
if
(
res
==
STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS
)
{
if
(
res
==
STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS
)
{
...
@@ -1790,13 +1939,16 @@ static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *
...
@@ -1790,13 +1939,16 @@ static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *
}
}
nice_address_set_from_sockaddr
(
&
niceaddr
,
&
relayaddr
);
nice_address_set_from_sockaddr
(
&
niceaddr
,
&
relayaddr
);
discovery_add_relay_candidate
(
relay_cand
=
discovery_add_relay_candidate
(
d
->
agent
,
d
->
agent
,
d
->
stream
->
id
,
d
->
stream
->
id
,
d
->
component
->
id
,
d
->
component
->
id
,
&
niceaddr
,
&
niceaddr
,
d
->
nicesock
);
d
->
nicesock
);
priv_add_new_turn_refresh
(
d
,
relay_cand
,
lifetime
);
d
->
stun_message
.
buffer
=
NULL
;
d
->
stun_message
.
buffer
=
NULL
;
d
->
stun_message
.
buffer_len
=
0
;
d
->
stun_message
.
buffer_len
=
0
;
d
->
done
=
TRUE
;
d
->
done
=
TRUE
;
...
@@ -1852,6 +2004,89 @@ static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *
...
@@ -1852,6 +2004,89 @@ static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *
}
}
/**
* Tries to match STUN reply in 'buf' to an existing STUN discovery
* transaction. If found, a reply is sent.
*
* @return TRUE if a matching transaction is found
*/
static
gboolean
priv_map_reply_to_relay_refresh
(
NiceAgent
*
agent
,
StunMessage
*
resp
)
{
uint32_t
lifetime
;
GSList
*
i
;
StunUsageTurnReturn
res
;
gboolean
trans_found
=
FALSE
;
stun_transid_t
refresh_id
;
stun_transid_t
response_id
;
stun_message_id
(
resp
,
response_id
);
for
(
i
=
agent
->
refresh_list
;
i
&&
trans_found
!=
TRUE
;
i
=
i
->
next
)
{
CandidateRefresh
*
cand
=
i
->
data
;
if
(
cand
->
stun_message
.
buffer
)
{
stun_message_id
(
&
cand
->
stun_message
,
refresh_id
);
if
(
memcmp
(
refresh_id
,
response_id
,
sizeof
(
stun_transid_t
))
==
0
)
{
res
=
stun_usage_turn_refresh_process
(
resp
,
&
lifetime
,
priv_agent_to_turn_compatibility
(
cand
->
agent
));
nice_debug
(
"Agent %p : stun_turn_refresh_process for %p res %d."
,
agent
,
cand
,
(
int
)
res
);
if
(
res
==
STUN_USAGE_TURN_RETURN_RELAY_SUCCESS
)
{
/* refresh should be sent 1 minute before it expires */
cand
->
timer_source
=
agent_timeout_add_with_context
(
cand
->
agent
,
(
lifetime
-
60
)
*
1000
,
priv_turn_allocate_refresh_tick
,
cand
);
g_source_destroy
(
cand
->
tick_source
);
g_source_unref
(
cand
->
tick_source
);
cand
->
tick_source
=
NULL
;
}
else
if
(
res
==
STUN_USAGE_TURN_RETURN_ERROR
)
{
int
code
=
-
1
;
uint8_t
*
sent_realm
=
NULL
;
uint8_t
*
recv_realm
=
NULL
;
uint16_t
sent_realm_len
=
0
;
uint16_t
recv_realm_len
=
0
;
sent_realm
=
(
uint8_t
*
)
stun_message_find
(
&
cand
->
stun_message
,
STUN_ATTRIBUTE_REALM
,
&
sent_realm_len
);
recv_realm
=
(
uint8_t
*
)
stun_message_find
(
resp
,
STUN_ATTRIBUTE_REALM
,
&
recv_realm_len
);
/* check for unauthorized error response */
if
(
cand
->
agent
->
compatibility
==
NICE_COMPATIBILITY_DRAFT19
&&
stun_message_get_class
(
resp
)
==
STUN_ERROR
&&
stun_message_find_error
(
resp
,
&
code
)
==
0
&&
recv_realm
!=
NULL
&&
recv_realm_len
>
0
)
{
if
(
code
==
438
||
(
code
==
401
&&
!
(
recv_realm_len
==
sent_realm_len
&&
sent_realm
!=
NULL
&&
memcmp
(
sent_realm
,
recv_realm
,
sent_realm_len
)
==
0
)))
{
cand
->
stun_resp_msg
=
*
resp
;
memcpy
(
cand
->
stun_resp_buffer
,
resp
->
buffer
,
stun_message_length
(
resp
));
cand
->
stun_resp_msg
.
buffer
=
cand
->
stun_resp_buffer
;
cand
->
stun_resp_msg
.
buffer_len
=
sizeof
(
cand
->
stun_resp_buffer
);
priv_turn_allocate_refresh_tick_unlocked
(
cand
);
}
else
{
/* case: a real unauthorized error */
refresh_cancel
(
cand
);
}
}
else
{
/* case: STUN error, the check STUN context was freed */
refresh_cancel
(
cand
);
}
trans_found
=
TRUE
;
}
}
}
}
return
trans_found
;
}
typedef
struct
{
typedef
struct
{
NiceAgent
*
agent
;
NiceAgent
*
agent
;
Stream
*
stream
;
Stream
*
stream
;
...
@@ -1979,7 +2214,7 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream,
...
@@ -1979,7 +2214,7 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream,
valid
=
stun_agent_validate
(
&
agent
->
stun_agent
,
&
req
,
valid
=
stun_agent_validate
(
&
agent
->
stun_agent
,
&
req
,
(
uint8_t
*
)
buf
,
len
,
conncheck_stun_validater
,
&
validater_data
);
(
uint8_t
*
)
buf
,
len
,
conncheck_stun_validater
,
&
validater_data
);
/* Check for relay candidates st
nu
agents */
/* Check for relay candidates st
un
agents */
if
(
valid
==
STUN_VALIDATION_BAD_REQUEST
||
if
(
valid
==
STUN_VALIDATION_BAD_REQUEST
||
valid
==
STUN_VALIDATION_UNMATCHED_RESPONSE
)
{
valid
==
STUN_VALIDATION_UNMATCHED_RESPONSE
)
{
for
(
i
=
agent
->
discovery_list
;
i
;
i
=
i
->
next
)
{
for
(
i
=
agent
->
discovery_list
;
i
;
i
=
i
->
next
)
{
...
@@ -1994,6 +2229,23 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream,
...
@@ -1994,6 +2229,23 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream,
}
}
}
}
}
}
/* Check for relay candidates stun agents */
if
(
valid
==
STUN_VALIDATION_BAD_REQUEST
||
valid
==
STUN_VALIDATION_UNMATCHED_RESPONSE
)
{
for
(
i
=
agent
->
refresh_list
;
i
;
i
=
i
->
next
)
{
CandidateRefresh
*
r
=
i
->
data
;
nice_debug
(
"Comparing %p to %p, %p to %p and %p and %p to %p"
,
r
->
stream
,
stream
,
r
->
component
,
component
,
r
->
nicesock
,
r
->
relay_socket
,
socket
);
if
(
r
->
stream
==
stream
&&
r
->
component
==
component
&&
(
r
->
nicesock
==
socket
||
r
->
relay_socket
==
socket
))
{
valid
=
stun_agent_validate
(
&
r
->
turn_agent
,
&
req
,
(
uint8_t
*
)
buf
,
len
,
conncheck_stun_validater
,
&
validater_data
);
nice_debug
(
"Validating gave %d"
,
valid
);
turn_msg
=
TRUE
;
break
;
}
}
}
if
(
validater_data
.
password
)
if
(
validater_data
.
password
)
...
@@ -2190,10 +2442,14 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream,
...
@@ -2190,10 +2442,14 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream,
if
(
trans_found
!=
TRUE
)
if
(
trans_found
!=
TRUE
)
trans_found
=
priv_map_reply_to_discovery_request
(
agent
,
&
req
);
trans_found
=
priv_map_reply_to_discovery_request
(
agent
,
&
req
);
/* step: let's try to match the response to an existing
discovery
*/
/* step: let's try to match the response to an existing
turn allocate
*/
if
(
trans_found
!=
TRUE
)
if
(
trans_found
!=
TRUE
)
trans_found
=
priv_map_reply_to_relay_request
(
agent
,
&
req
);
trans_found
=
priv_map_reply_to_relay_request
(
agent
,
&
req
);
/* step: let's try to match the response to an existing turn refresh */
if
(
trans_found
!=
TRUE
)
trans_found
=
priv_map_reply_to_relay_refresh
(
agent
,
&
req
);
if
(
trans_found
!=
TRUE
)
if
(
trans_found
!=
TRUE
)
nice_debug
(
"Agent %p : Unable to match to an existing transaction, "
nice_debug
(
"Agent %p : Unable to match to an existing transaction, "
"probably a keepalive."
,
agent
);
"probably a keepalive."
,
agent
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment