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
a13ac437
Commit
a13ac437
authored
May 13, 2021
by
Ole André Vadla Ravnås
Committed by
Olivier Crête
Nov 22, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
agent: Add support for bytestream TCP
parent
7bd11cf0
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
610 additions
and
173 deletions
+610
-173
agent/agent-priv.h
agent/agent-priv.h
+1
-1
agent/agent.c
agent/agent.c
+380
-154
agent/agent.h
agent/agent.h
+2
-0
agent/component.c
agent/component.c
+19
-3
agent/component.h
agent/component.h
+13
-0
tests/meson.build
tests/meson.build
+2
-1
tests/test-bytestream-tcp.c
tests/test-bytestream-tcp.c
+130
-0
tests/test-io-stream-cancelling.c
tests/test-io-stream-cancelling.c
+1
-1
tests/test-io-stream-closing-read.c
tests/test-io-stream-closing-read.c
+2
-1
tests/test-io-stream-closing-write.c
tests/test-io-stream-closing-write.c
+2
-1
tests/test-io-stream-common.c
tests/test-io-stream-common.c
+45
-7
tests/test-io-stream-common.h
tests/test-io-stream-common.h
+8
-1
tests/test-io-stream-pollable.c
tests/test-io-stream-pollable.c
+1
-1
tests/test-io-stream-thread.c
tests/test-io-stream-thread.c
+1
-1
tests/test-send-recv.c
tests/test-send-recv.c
+3
-1
No files found.
agent/agent-priv.h
View file @
a13ac437
...
@@ -178,10 +178,10 @@ struct _NiceAgent
...
@@ -178,10 +178,10 @@ struct _NiceAgent
#endif
#endif
gchar
*
software_attribute
;
/* SOFTWARE attribute */
gchar
*
software_attribute
;
/* SOFTWARE attribute */
gboolean
reliable
;
/* property: reliable */
gboolean
reliable
;
/* property: reliable */
gboolean
bytestream_tcp
;
/* property: bytestream-tcp */
gboolean
keepalive_conncheck
;
/* property: keepalive_conncheck */
gboolean
keepalive_conncheck
;
/* property: keepalive_conncheck */
GQueue
pending_signals
;
GQueue
pending_signals
;
guint16
rfc4571_expecting_length
;
gboolean
use_ice_udp
;
gboolean
use_ice_udp
;
gboolean
use_ice_tcp
;
gboolean
use_ice_tcp
;
gboolean
use_ice_trickle
;
gboolean
use_ice_trickle
;
...
...
agent/agent.c
View file @
a13ac437
...
@@ -82,9 +82,17 @@
...
@@ -82,9 +82,17 @@
#define MAX_TCP_MTU 1400
/* Use 1400 because of VPNs and we assume IEE 802.3 */
#define MAX_TCP_MTU 1400
/* Use 1400 because of VPNs and we assume IEE 802.3 */
static
void
agent_consume_next_rfc4571_chunk
(
NiceAgent
*
agent
,
NiceComponent
*
component
,
NiceInputMessage
*
messages
,
guint
n_messages
,
NiceInputMessageIter
*
iter
);
static
void
static
void
nice_debug_input_message_composition
(
const
NiceInputMessage
*
messages
,
nice_debug_input_message_composition
(
const
NiceInputMessage
*
messages
,
guint
n_messages
);
guint
n_messages
);
static
gsize
append_buffer_to_input_messages
(
gboolean
bytestream_tcp
,
NiceInputMessage
*
messages
,
guint
n_messages
,
NiceInputMessageIter
*
iter
,
const
guint8
*
buffer
,
gsize
buffer_length
);
static
gsize
nice_input_message_iter_get_message_capacity
(
NiceInputMessageIter
*
iter
,
NiceInputMessage
*
messages
,
guint
n_messages
);
static
const
gchar
*
_cand_type_to_sdp
(
NiceCandidateType
type
);
static
const
gchar
*
_cand_type_to_sdp
(
NiceCandidateType
type
);
G_DEFINE_TYPE
(
NiceAgent
,
nice_agent
,
G_TYPE_OBJECT
);
G_DEFINE_TYPE
(
NiceAgent
,
nice_agent
,
G_TYPE_OBJECT
);
...
@@ -151,6 +159,7 @@ static PseudoTcpWriteResult pseudo_tcp_socket_write_packet (PseudoTcpSocket *soc
...
@@ -151,6 +159,7 @@ static PseudoTcpWriteResult pseudo_tcp_socket_write_packet (PseudoTcpSocket *soc
const
gchar
*
buffer
,
guint32
len
,
gpointer
user_data
);
const
gchar
*
buffer
,
guint32
len
,
gpointer
user_data
);
static
void
adjust_tcp_clock
(
NiceAgent
*
agent
,
NiceStream
*
stream
,
NiceComponent
*
component
);
static
void
adjust_tcp_clock
(
NiceAgent
*
agent
,
NiceStream
*
stream
,
NiceComponent
*
component
);
static
void
nice_agent_constructed
(
GObject
*
object
);
static
void
nice_agent_dispose
(
GObject
*
object
);
static
void
nice_agent_dispose
(
GObject
*
object
);
static
void
nice_agent_get_property
(
GObject
*
object
,
static
void
nice_agent_get_property
(
GObject
*
object
,
guint
property_id
,
GValue
*
value
,
GParamSpec
*
pspec
);
guint
property_id
,
GValue
*
value
,
GParamSpec
*
pspec
);
...
@@ -352,6 +361,7 @@ nice_agent_class_init (NiceAgentClass *klass)
...
@@ -352,6 +361,7 @@ nice_agent_class_init (NiceAgentClass *klass)
{
{
GObjectClass
*
gobject_class
=
G_OBJECT_CLASS
(
klass
);
GObjectClass
*
gobject_class
=
G_OBJECT_CLASS
(
klass
);
gobject_class
->
constructed
=
nice_agent_constructed
;
gobject_class
->
get_property
=
nice_agent_get_property
;
gobject_class
->
get_property
=
nice_agent_get_property
;
gobject_class
->
set_property
=
nice_agent_set_property
;
gobject_class
->
set_property
=
nice_agent_set_property
;
gobject_class
->
dispose
=
nice_agent_dispose
;
gobject_class
->
dispose
=
nice_agent_dispose
;
...
@@ -727,7 +737,7 @@ nice_agent_class_init (NiceAgentClass *klass)
...
@@ -727,7 +737,7 @@ nice_agent_class_init (NiceAgentClass *klass)
/**
/**
* NiceAgent:bytestream-tcp:
* NiceAgent:bytestream-tcp:
*
*
* This property defines whether receive/send o
ver a TCP or pseudo-TCP
, in
* This property defines whether receive/send o
perations over a TCP socket
, in
* reliable mode, are considered as packetized or as bytestream.
* reliable mode, are considered as packetized or as bytestream.
* In unreliable mode, every send/recv is considered as packetized, and
* In unreliable mode, every send/recv is considered as packetized, and
* this property is ignored and cannot be set.
* this property is ignored and cannot be set.
...
@@ -737,15 +747,11 @@ nice_agent_class_init (NiceAgentClass *klass)
...
@@ -737,15 +747,11 @@ nice_agent_class_init (NiceAgentClass *klass)
* </para>
* </para>
* If the property is %TRUE, the stream is considered in bytestream mode
* If the property is %TRUE, the stream is considered in bytestream mode
* and data can be read with any receive size. If the property is %FALSE, then
* and data can be read with any receive size. If the property is %FALSE, then
* the stream is considred packetized and each receive will return one packet
* the stream is consid
e
red packetized and each receive will return one packet
* of the same size as what was sent from the peer. If in packetized mode,
* of the same size as what was sent from the peer. If in packetized mode,
* then doing a receive with a size smaller than the packet, will cause the
* then doing a receive with a size smaller than the packet, will cause the
* remaining bytes in the packet to be dropped, breaking the reliability
* remaining bytes in the packet to be dropped, breaking the reliability
* of the stream.
* of the stream.
* <para>
* This property is currently read-only, and will become read/write once
* bytestream mode will be supported.
* </para>
*
*
* Since: 0.1.8
* Since: 0.1.8
*/
*/
...
@@ -753,9 +759,9 @@ nice_agent_class_init (NiceAgentClass *klass)
...
@@ -753,9 +759,9 @@ nice_agent_class_init (NiceAgentClass *klass)
g_param_spec_boolean
(
g_param_spec_boolean
(
"bytestream-tcp"
,
"bytestream-tcp"
,
"Bytestream TCP"
,
"Bytestream TCP"
,
"Use bytestream mode for reliable TCP
and Pseudo-TCP
connections"
,
"Use bytestream mode for reliable TCP connections"
,
FALSE
,
FALSE
,
G_PARAM_READ
ABL
E
));
G_PARAM_READ
WRIT
E
));
/**
/**
* NiceAgent:keepalive-conncheck:
* NiceAgent:keepalive-conncheck:
...
@@ -1283,6 +1289,7 @@ nice_agent_init (NiceAgent *agent)
...
@@ -1283,6 +1289,7 @@ nice_agent_init (NiceAgent *agent)
agent
->
compatibility
=
NICE_COMPATIBILITY_RFC5245
;
agent
->
compatibility
=
NICE_COMPATIBILITY_RFC5245
;
agent
->
reliable
=
FALSE
;
agent
->
reliable
=
FALSE
;
agent
->
bytestream_tcp
=
FALSE
;
agent
->
use_ice_udp
=
TRUE
;
agent
->
use_ice_udp
=
TRUE
;
agent
->
use_ice_tcp
=
TRUE
;
agent
->
use_ice_tcp
=
TRUE
;
...
@@ -1294,6 +1301,17 @@ nice_agent_init (NiceAgent *agent)
...
@@ -1294,6 +1301,17 @@ nice_agent_init (NiceAgent *agent)
g_mutex_init
(
&
agent
->
agent_mutex
);
g_mutex_init
(
&
agent
->
agent_mutex
);
}
}
static
void
nice_agent_constructed
(
GObject
*
object
)
{
NiceAgent
*
agent
=
NICE_AGENT
(
object
);
if
(
agent
->
reliable
&&
agent
->
compatibility
==
NICE_COMPATIBILITY_GOOGLE
)
agent
->
bytestream_tcp
=
TRUE
;
G_OBJECT_CLASS
(
nice_agent_parent_class
)
->
constructed
(
object
);
}
NICEAPI_EXPORT
NiceAgent
*
NICEAPI_EXPORT
NiceAgent
*
nice_agent_new
(
GMainContext
*
ctx
,
NiceCompatibility
compat
)
nice_agent_new
(
GMainContext
*
ctx
,
NiceCompatibility
compat
)
...
@@ -1318,6 +1336,7 @@ nice_agent_new_full (GMainContext *ctx,
...
@@ -1318,6 +1336,7 @@ nice_agent_new_full (GMainContext *ctx,
"compatibility"
,
compat
,
"compatibility"
,
compat
,
"main-context"
,
ctx
,
"main-context"
,
ctx
,
"reliable"
,
(
flags
&
NICE_AGENT_OPTION_RELIABLE
)
?
TRUE
:
FALSE
,
"reliable"
,
(
flags
&
NICE_AGENT_OPTION_RELIABLE
)
?
TRUE
:
FALSE
,
"bytestream-tcp"
,
(
flags
&
NICE_AGENT_OPTION_BYTESTREAM_TCP
)
?
TRUE
:
FALSE
,
"nomination-mode"
,
(
flags
&
NICE_AGENT_OPTION_REGULAR_NOMINATION
)
?
"nomination-mode"
,
(
flags
&
NICE_AGENT_OPTION_REGULAR_NOMINATION
)
?
NICE_NOMINATION_MODE_REGULAR
:
NICE_NOMINATION_MODE_AGGRESSIVE
,
NICE_NOMINATION_MODE_REGULAR
:
NICE_NOMINATION_MODE_AGGRESSIVE
,
"full-mode"
,
(
flags
&
NICE_AGENT_OPTION_LITE_MODE
)
?
FALSE
:
TRUE
,
"full-mode"
,
(
flags
&
NICE_AGENT_OPTION_LITE_MODE
)
?
FALSE
:
TRUE
,
...
@@ -1437,14 +1456,7 @@ nice_agent_get_property (
...
@@ -1437,14 +1456,7 @@ nice_agent_get_property (
break
;
break
;
case
PROP_BYTESTREAM_TCP
:
case
PROP_BYTESTREAM_TCP
:
if
(
agent
->
reliable
)
{
g_value_set_boolean
(
value
,
agent
->
bytestream_tcp
);
if
(
agent
->
compatibility
==
NICE_COMPATIBILITY_GOOGLE
)
g_value_set_boolean
(
value
,
TRUE
);
else
g_value_set_boolean
(
value
,
FALSE
);
}
else
{
g_value_set_boolean
(
value
,
FALSE
);
}
break
;
break
;
case
PROP_KEEPALIVE_CONNCHECK
:
case
PROP_KEEPALIVE_CONNCHECK
:
...
@@ -1669,7 +1681,8 @@ nice_agent_set_property (
...
@@ -1669,7 +1681,8 @@ nice_agent_set_property (
break
;
break
;
case
PROP_BYTESTREAM_TCP
:
case
PROP_BYTESTREAM_TCP
:
/* TODO: support bytestream mode and set property to writable */
if
(
agent
->
reliable
&&
agent
->
compatibility
!=
NICE_COMPATIBILITY_GOOGLE
)
agent
->
bytestream_tcp
=
g_value_get_boolean
(
value
);
break
;
break
;
case
PROP_KEEPALIVE_CONNCHECK
:
case
PROP_KEEPALIVE_CONNCHECK
:
...
@@ -4194,6 +4207,9 @@ agent_recv_message_unlocked (
...
@@ -4194,6 +4207,9 @@ agent_recv_message_unlocked (
NiceSocket
*
nicesock
,
NiceSocket
*
nicesock
,
NiceInputMessage
*
message
)
NiceInputMessage
*
message
)
{
{
NiceInputMessage
*
provided_message
=
message
;
NiceInputMessage
rfc4571_message
;
GInputVector
rfc4571_buf
;
NiceAddress
from
;
NiceAddress
from
;
RecvStatus
retval
;
RecvStatus
retval
;
gint
sockret
;
gint
sockret
;
...
@@ -4281,112 +4297,103 @@ agent_recv_message_unlocked (
...
@@ -4281,112 +4297,103 @@ agent_recv_message_unlocked (
/* In the case of a real ICE-TCP connection, we can use the socket as a
/* In the case of a real ICE-TCP connection, we can use the socket as a
* bytestream and do the read here with caching of data being read
* bytestream and do the read here with caching of data being read
*/
*/
gssize
available
=
g_socket_get_available_bytes
(
nicesock
->
fileno
);
guint
headroom
;
gboolean
missing_cached_data
,
have_whole_frame
;
/* TODO: Support bytestream reads */
message
->
length
=
0
;
sockret
=
0
;
sockret
=
0
;
if
(
available
<=
0
)
{
message
->
length
=
0
;
sockret
=
available
;
/* If we don't call check_connect_result on an outbound connection,
headroom
=
nice_component_compute_rfc4571_headroom
(
component
);
* then is_connected will always return FALSE. That's why we check
missing_cached_data
=
component
->
rfc4571_frame_size
==
0
||
* both conditions to make sure g_socket_is_connected returns the
headroom
<
component
->
rfc4571_frame_size
;
* correct result, otherwise we end up closing valid connections
*/
if
(
missing_cached_data
)
{
if
(
g_socket_check_connect_result
(
nicesock
->
fileno
,
NULL
)
==
FALSE
||
gssize
available
=
g_socket_get_available_bytes
(
nicesock
->
fileno
);
g_socket_is_connected
(
nicesock
->
fileno
)
==
FALSE
)
{
/* If we receive a readable event on a TCP_BSD socket which is
if
(
available
<=
0
)
{
* not connected, it means that it failed to connect, so we must
sockret
=
available
;
* return an error to make the socket fail/closed
*/
/* If we don't call check_connect_result on an outbound connection,
sockret
=
-
1
;
* then is_connected will always return FALSE. That's why we check
}
else
{
* both conditions to make sure g_socket_is_connected returns the
gint
flags
=
G_SOCKET_MSG_PEEK
;
* correct result, otherwise we end up closing valid connections
/* If available bytes are 0, but the socket is still considered
* connected, then either we're just trying to see if there's more
* data available or the peer closed the connection.
* The only way to know is to do a read, so we do here a peek and
* check the return value, if it's 0, it means the peer has closed
* the connection, so we must return an error instead of WOULD_BLOCK
*/
*/
if
(
g_socket_receive_message
(
nicesock
->
fileno
,
NULL
,
if
(
!
g_socket_check_connect_result
(
nicesock
->
fileno
,
NULL
)
||
NULL
,
0
,
NULL
,
NULL
,
&
flags
,
NULL
,
NULL
)
==
0
)
!
g_socket_is_connected
(
nicesock
->
fileno
))
{
/* If we receive a readable event on a TCP_BSD socket which is
* not connected, it means that it failed to connect, so we must
* return an error to make the socket fail/closed
*/
sockret
=
-
1
;
sockret
=
-
1
;
}
}
else
{
}
else
if
(
agent
->
rfc4571_expecting_length
==
0
)
{
gint
flags
=
G_SOCKET_MSG_PEEK
;
if
((
gsize
)
available
>=
sizeof
(
guint16
))
{
guint16
rfc4571_frame
;
/* If available bytes are 0, but the socket is still considered
GInputVector
local_buf
=
{
&
rfc4571_frame
,
sizeof
(
guint16
)};
* connected, then either we're just trying to see if there's more
NiceInputMessage
local_message
=
{
&
local_buf
,
1
,
message
->
from
,
0
};
* data available or the peer closed the connection.
* The only way to know is to do a read, so we do here a peek and
* check the return value, if it's 0, it means the peer has closed
* the connection, so we must return an error instead of
* WOULD_BLOCK
*/
if
(
g_socket_receive_message
(
nicesock
->
fileno
,
NULL
,
NULL
,
0
,
NULL
,
NULL
,
&
flags
,
NULL
,
NULL
)
==
0
)
sockret
=
-
1
;
}
}
else
{
GInputVector
local_buf
=
{
component
->
rfc4571_buffer
,
component
->
rfc4571_buffer_size
};
NiceInputMessage
local_message
=
{
&
local_buf
,
1
,
&
component
->
rfc4571_remote_addr
,
0
};
if
(
headroom
>
0
)
{
memmove
(
component
->
rfc4571_buffer
,
component
->
rfc4571_buffer
+
component
->
rfc4571_frame_offset
,
headroom
);
local_buf
.
buffer
=
(
guint8
*
)
local_buf
.
buffer
+
headroom
;
local_buf
.
size
-=
headroom
;
}
component
->
rfc4571_buffer_offset
=
headroom
;
component
->
rfc4571_frame_offset
=
0
;
sockret
=
nice_socket_recv_messages
(
nicesock
,
&
local_message
,
1
);
sockret
=
nice_socket_recv_messages
(
nicesock
,
&
local_message
,
1
);
if
(
sockret
==
1
&&
local_message
.
length
>=
sizeof
(
guint16
)
)
{
if
(
sockret
==
1
)
{
agent
->
rfc4571_expecting_length
=
ntohs
(
rfc4571_frame
)
;
component
->
rfc4571_buffer_offset
+=
local_message
.
length
;
available
=
g_socket_get_available_bytes
(
nicesock
->
fileno
)
;
headroom
+=
local_message
.
length
;
}
}
}
}
}
if
(
agent
->
rfc4571_expecting_length
>
0
)
{
GInputVector
*
local_bufs
;
NiceInputMessage
local_message
;
gsize
off
;
guint
n_bufs
=
0
;
guint
i
;
/* Count the number of buffers. */
if
(
component
->
rfc4571_frame_size
==
0
&&
if
(
message
->
n_buffers
==
-
1
)
{
headroom
>=
sizeof
(
guint16
))
{
for
(
i
=
0
;
message
->
buffers
[
i
].
buffer
!=
NULL
;
i
++
)
component
->
rfc4571_frame_size
=
sizeof
(
guint16
)
+
ntohs
(
n_bufs
++
;
*
((
guint16
*
)
(
component
->
rfc4571_buffer
+
}
else
{
component
->
rfc4571_frame_offset
)));
n_bufs
=
message
->
n_buffers
;
}
}
}
local_bufs
=
g_alloca
(
n_bufs
*
sizeof
(
GInputVector
));
have_whole_frame
=
component
->
rfc4571_frame_size
!=
0
&&
local_message
.
buffers
=
local_bufs
;
headroom
>=
component
->
rfc4571_frame_size
;
local_message
.
from
=
message
->
from
;
if
(
have_whole_frame
)
{
local_message
.
length
=
0
;
rfc4571_buf
.
buffer
=
component
->
rfc4571_buffer
+
local_message
.
n_buffers
=
0
;
component
->
rfc4571_frame_offset
+
sizeof
(
guint16
);
rfc4571_buf
.
size
=
component
->
rfc4571_frame_size
-
sizeof
(
guint16
);
/* Only read up to the expected number of bytes in the frame */
off
=
0
;
for
(
i
=
0
;
i
<
n_bufs
;
i
++
)
{
if
(
message
->
buffers
[
i
].
size
+
off
<
message
->
length
)
{
/* Skip already full buffers */
off
+=
message
->
buffers
[
i
].
size
;
}
else
{
gssize
diff
=
0
;
/* If we have a partially full buffer, offset the pointer */
rfc4571_message
.
buffers
=
&
rfc4571_buf
;
if
(
off
<
message
->
length
)
rfc4571_message
.
n_buffers
=
1
;
diff
=
message
->
length
-
off
;
rfc4571_message
.
from
=
provided_message
->
from
;
rfc4571_message
.
length
=
rfc4571_buf
.
size
;
/* Those buffers are filled */
message
=
&
rfc4571_message
;
local_bufs
[
local_message
.
n_buffers
].
buffer
=
*
message
->
from
=
component
->
rfc4571_remote_addr
;
((
char
*
)
message
->
buffers
[
i
].
buffer
)
+
diff
;
local_bufs
[
local_message
.
n_buffers
].
size
=
MIN
(
message
->
buffers
[
i
].
size
-
diff
,
agent
->
rfc4571_expecting_length
-
off
);
off
+=
local_message
.
buffers
[
local_message
.
n_buffers
].
size
;
local_message
.
n_buffers
++
;
/* If we have a big enough buffer, let's just stop */
sockret
=
1
;
if
(
off
==
message
->
length
+
agent
->
rfc4571_expecting_length
)
}
else
{
break
;
if
(
sockret
==
1
)
}
sockret
=
0
;
}
sockret
=
nice_socket_recv_messages
(
nicesock
,
&
local_message
,
1
);
if
(
sockret
==
1
)
{
message
->
length
+=
local_message
.
length
;
agent
->
rfc4571_expecting_length
-=
local_message
.
length
;
if
(
agent
->
rfc4571_expecting_length
!=
0
)
{
retval
=
RECV_WOULD_BLOCK
;
/* EWOULDBLOCK */
nice_debug_verbose
(
"%s: Agent %p: TCP message incomplete"
,
G_STRFUNC
,
agent
);
goto
done
;
}
}
}
}
}
}
}
}
...
@@ -4539,6 +4546,16 @@ agent_recv_message_unlocked (
...
@@ -4539,6 +4546,16 @@ agent_recv_message_unlocked (
}
}
done:
done:
if
(
message
==
&
rfc4571_message
)
{
if
(
retval
==
RECV_SUCCESS
)
{
NiceInputMessageIter
iter
=
{
0
,
0
,
0
};
agent_consume_next_rfc4571_chunk
(
agent
,
component
,
provided_message
,
1
,
&
iter
);
}
else
{
agent_consume_next_rfc4571_chunk
(
agent
,
component
,
NULL
,
0
,
NULL
);
}
}
/* Clear local modifications. */
/* Clear local modifications. */
if
(
message
->
from
==
&
from
)
{
if
(
message
->
from
==
&
from
)
{
message
->
from
=
NULL
;
message
->
from
=
NULL
;
...
@@ -4547,6 +4564,75 @@ done:
...
@@ -4547,6 +4564,75 @@ done:
return
retval
;
return
retval
;
}
}
static
void
agent_consume_next_rfc4571_chunk
(
NiceAgent
*
agent
,
NiceComponent
*
component
,
NiceInputMessage
*
messages
,
guint
n_messages
,
NiceInputMessageIter
*
iter
)
{
gboolean
fully_consumed
;
if
(
messages
!=
NULL
)
{
gsize
bytes_unconsumed
,
bytes_copied
;
bytes_unconsumed
=
component
->
rfc4571_frame_size
-
sizeof
(
guint16
)
-
component
->
rfc4571_consumed_size
;
bytes_copied
=
append_buffer_to_input_messages
(
agent
->
bytestream_tcp
,
messages
,
n_messages
,
iter
,
component
->
rfc4571_buffer
+
component
->
rfc4571_frame_offset
+
component
->
rfc4571_frame_size
-
bytes_unconsumed
,
bytes_unconsumed
);
component
->
rfc4571_consumed_size
+=
bytes_copied
;
fully_consumed
=
bytes_copied
==
bytes_unconsumed
||
!
agent
->
bytestream_tcp
;
}
else
{
fully_consumed
=
TRUE
;
}
if
(
fully_consumed
)
{
guint
headroom
;
gboolean
have_whole_next_frame
;
component
->
rfc4571_frame_offset
+=
component
->
rfc4571_frame_size
;
component
->
rfc4571_frame_size
=
0
;
component
->
rfc4571_consumed_size
=
0
;
headroom
=
nice_component_compute_rfc4571_headroom
(
component
);
if
(
headroom
>=
sizeof
(
guint16
))
{
component
->
rfc4571_frame_size
=
sizeof
(
guint16
)
+
ntohs
(
*
((
guint16
*
)
(
component
->
rfc4571_buffer
+
component
->
rfc4571_frame_offset
)));
have_whole_next_frame
=
headroom
>=
component
->
rfc4571_frame_size
;
}
else
{
have_whole_next_frame
=
FALSE
;
}
component
->
rfc4571_wakeup_needed
=
have_whole_next_frame
;
}
else
{
component
->
rfc4571_wakeup_needed
=
TRUE
;
}
}
static
gboolean
agent_try_consume_next_rfc4571_chunk
(
NiceAgent
*
agent
,
NiceComponent
*
component
,
NiceInputMessage
*
messages
,
guint
n_messages
,
NiceInputMessageIter
*
iter
)
{
guint
headroom
;
if
(
component
->
rfc4571_frame_size
==
0
)
return
FALSE
;
headroom
=
nice_component_compute_rfc4571_headroom
(
component
);
if
(
headroom
<
component
->
rfc4571_frame_size
)
return
FALSE
;
agent_consume_next_rfc4571_chunk
(
agent
,
component
,
messages
,
n_messages
,
iter
);
return
TRUE
;
}
/* Print the composition of an array of messages. No-op if debugging is
/* Print the composition of an array of messages. No-op if debugging is
* disabled. */
* disabled. */
static
void
static
void
...
@@ -4657,6 +4743,48 @@ memcpy_buffer_to_input_message (NiceInputMessage *message,
...
@@ -4657,6 +4743,48 @@ memcpy_buffer_to_input_message (NiceInputMessage *message,
return
message
->
length
;
return
message
->
length
;
}
}
static
gsize
append_buffer_to_input_messages
(
gboolean
bytestream_tcp
,
NiceInputMessage
*
messages
,
guint
n_messages
,
NiceInputMessageIter
*
iter
,
const
guint8
*
buffer
,
gsize
buffer_length
)
{
NiceInputMessage
*
message
=
&
messages
[
iter
->
message
];
gsize
buffer_offset
;
if
(
iter
->
buffer
==
0
&&
iter
->
offset
==
0
)
{
message
->
length
=
0
;
}
for
(
buffer_offset
=
0
;
(
message
->
n_buffers
>=
0
&&
iter
->
buffer
<
(
guint
)
message
->
n_buffers
)
||
(
message
->
n_buffers
<
0
&&
message
->
buffers
[
iter
->
buffer
].
buffer
!=
NULL
);
iter
->
buffer
++
)
{
GInputVector
*
v
=
&
message
->
buffers
[
iter
->
buffer
];
gsize
len
;
len
=
MIN
(
buffer_length
-
buffer_offset
,
v
->
size
-
iter
->
offset
);
memcpy
((
guint8
*
)
v
->
buffer
+
iter
->
offset
,
buffer
+
buffer_offset
,
len
);
message
->
length
+=
len
;
iter
->
offset
+=
len
;
buffer_offset
+=
len
;
if
(
buffer_offset
==
buffer_length
)
break
;
iter
->
offset
=
0
;
}
if
(
!
bytestream_tcp
||
nice_input_message_iter_get_message_capacity
(
iter
,
messages
,
n_messages
)
==
0
)
{
iter
->
offset
=
0
;
iter
->
buffer
=
0
;
iter
->
message
++
;
}
return
buffer_offset
;
}
/* Concatenate all the buffers in the given @message into a single, newly
/* Concatenate all the buffers in the given @message into a single, newly
* allocated, monolithic buffer which is returned. The length of the new buffer
* allocated, monolithic buffer which is returned. The length of the new buffer
* is returned in @buffer_length, and should be equal to the length field of
* is returned in @buffer_length, and should be equal to the length field of
...
@@ -4764,6 +4892,28 @@ nice_input_message_iter_get_n_valid_messages (NiceInputMessageIter *iter)
...
@@ -4764,6 +4892,28 @@ nice_input_message_iter_get_n_valid_messages (NiceInputMessageIter *iter)
return
iter
->
message
+
1
;
return
iter
->
message
+
1
;
}
}
static
gsize
nice_input_message_iter_get_message_capacity
(
NiceInputMessageIter
*
iter
,
NiceInputMessage
*
messages
,
guint
n_messages
)
{
NiceInputMessage
*
message
=
&
messages
[
iter
->
message
];
guint
i
;
gsize
total
;
if
(
iter
->
message
==
n_messages
)
return
0
;
total
=
0
;
for
(
i
=
iter
->
buffer
;
(
message
->
n_buffers
>=
0
&&
i
<
(
guint
)
message
->
n_buffers
)
||
(
message
->
n_buffers
<
0
&&
message
->
buffers
[
i
].
buffer
!=
NULL
);
i
++
)
{
total
+=
message
->
buffers
[
i
].
size
;
}
return
total
-
iter
->
offset
;
}
/**
/**
* nice_input_message_iter_compare:
* nice_input_message_iter_compare:
* @a: a #NiceInputMessageIter
* @a: a #NiceInputMessageIter
...
@@ -4784,9 +4934,8 @@ nice_input_message_iter_compare (const NiceInputMessageIter *a,
...
@@ -4784,9 +4934,8 @@ nice_input_message_iter_compare (const NiceInputMessageIter *a,
}
}
/* Will fill up @messages from the first free byte onwards (as determined using
/* Will fill up @messages from the first free byte onwards (as determined using
* @iter). This may be used in reliable or non-reliable mode; in non-reliable
* @iter). This may be used in bytestream or packetized mode; in packetized mode
* mode it will always increment the message index after each buffer is
* it will always increment the message index after each buffer is consumed.
* consumed.
*
*
* Updates @iter in place. No errors can occur.
* Updates @iter in place. No errors can occur.
*
*
...
@@ -4795,12 +4944,12 @@ nice_input_message_iter_compare (const NiceInputMessageIter *a,
...
@@ -4795,12 +4944,12 @@ nice_input_message_iter_compare (const NiceInputMessageIter *a,
*
*
* Must be called with the io_mutex held. */
* Must be called with the io_mutex held. */
static
gint
static
gint
pending_io_messages_recv_messages
(
NiceComponent
*
component
,
gboolean
reliable
,
pending_io_messages_recv_messages
(
NiceComponent
*
component
,
NiceInputMessage
*
messages
,
guint
n_messages
,
NiceInputMessageIter
*
iter
)
gboolean
bytestream_tcp
,
NiceInputMessage
*
messages
,
guint
n_messages
,
NiceInputMessageIter
*
iter
)
{
{
gsize
len
;
IOCallbackData
*
data
;
IOCallbackData
*
data
;
NiceInputMessage
*
message
=
&
messages
[
iter
->
message
]
;
gsize
bytes_copied
;
g_assert
(
component
->
io_callback_id
==
0
);
g_assert
(
component
->
io_callback_id
==
0
);
...
@@ -4808,47 +4957,13 @@ pending_io_messages_recv_messages (NiceComponent *component, gboolean reliable,
...
@@ -4808,47 +4957,13 @@ pending_io_messages_recv_messages (NiceComponent *component, gboolean reliable,
if
(
data
==
NULL
)
if
(
data
==
NULL
)
goto
done
;
goto
done
;
if
(
iter
->
buffer
==
0
&&
iter
->
offset
==
0
)
{
bytes_copied
=
append_buffer_to_input_messages
(
bytestream_tcp
,
messages
,
message
->
length
=
0
;
n_messages
,
iter
,
data
->
buf
+
data
->
offset
,
data
->
buf_len
-
data
->
offset
);
}
data
->
offset
+=
bytes_copied
;
for
(;
(
message
->
n_buffers
>=
0
&&
iter
->
buffer
<
(
guint
)
message
->
n_buffers
)
||
(
message
->
n_buffers
<
0
&&
message
->
buffers
[
iter
->
buffer
].
buffer
!=
NULL
);
iter
->
buffer
++
)
{
GInputVector
*
buffer
=
&
message
->
buffers
[
iter
->
buffer
];
do
{
len
=
MIN
(
data
->
buf_len
-
data
->
offset
,
buffer
->
size
-
iter
->
offset
);
memcpy
((
guint8
*
)
buffer
->
buffer
+
iter
->
offset
,
data
->
buf
+
data
->
offset
,
len
);
nice_debug
(
"%s: Unbuffered %"
G_GSIZE_FORMAT
" bytes into "
"buffer %p (offset %"
G_GSIZE_FORMAT
", length %"
G_GSIZE_FORMAT
")."
,
G_STRFUNC
,
len
,
buffer
->
buffer
,
iter
->
offset
,
buffer
->
size
);
message
->
length
+=
len
;
iter
->
offset
+=
len
;
data
->
offset
+=
len
;
}
while
(
iter
->
offset
<
buffer
->
size
);
iter
->
offset
=
0
;
}
/* Only if we managed to consume the whole buffer should it be popped off the
if
(
!
bytestream_tcp
||
data
->
offset
==
data
->
buf_len
)
{
* queue; otherwise we’ll have another go at it later. */
if
(
data
->
offset
==
data
->
buf_len
)
{
g_queue_pop_head
(
&
component
->
pending_io_messages
);
g_queue_pop_head
(
&
component
->
pending_io_messages
);
io_callback_data_free
(
data
);
io_callback_data_free
(
data
);
/* If we’ve consumed an entire message from pending_io_messages, and
* are in non-reliable mode, move on to the next message in
* @messages. */
if
(
!
reliable
)
{
iter
->
offset
=
0
;
iter
->
buffer
=
0
;
iter
->
message
++
;
}
}
}
done:
done:
...
@@ -4957,7 +5072,7 @@ nice_agent_recv_messages_blocking_or_nonblocking (NiceAgent *agent,
...
@@ -4957,7 +5072,7 @@ nice_agent_recv_messages_blocking_or_nonblocking (NiceAgent *agent,
while
(
!
received_enough
&&
while
(
!
received_enough
&&
!
g_queue_is_empty
(
&
component
->
pending_io_messages
))
{
!
g_queue_is_empty
(
&
component
->
pending_io_messages
))
{
pending_io_messages_recv_messages
(
component
,
agent
->
reliable
,
pending_io_messages_recv_messages
(
component
,
agent
->
bytestream_tcp
,
component
->
recv_messages
,
component
->
n_recv_messages
,
component
->
recv_messages
,
component
->
n_recv_messages
,
&
component
->
recv_messages_iter
);
&
component
->
recv_messages_iter
);
...
@@ -4973,6 +5088,15 @@ nice_agent_recv_messages_blocking_or_nonblocking (NiceAgent *agent,
...
@@ -4973,6 +5088,15 @@ nice_agent_recv_messages_blocking_or_nonblocking (NiceAgent *agent,
g_mutex_unlock
(
&
component
->
io_mutex
);
g_mutex_unlock
(
&
component
->
io_mutex
);
if
(
!
received_enough
&&
agent_try_consume_next_rfc4571_chunk
(
agent
,
component
,
component
->
recv_messages
,
component
->
n_recv_messages
,
&
component
->
recv_messages_iter
))
{
n_valid_messages
=
nice_input_message_iter_get_n_valid_messages
(
&
component
->
recv_messages_iter
);
nice_component_set_io_callback
(
component
,
NULL
,
NULL
,
NULL
,
0
,
NULL
);
goto
done
;
}
/* For a reliable stream, grab any data from the pseudo-TCP input buffer
/* For a reliable stream, grab any data from the pseudo-TCP input buffer
* before trying the sockets. */
* before trying the sockets. */
if
(
agent
->
reliable
&&
if
(
agent
->
reliable
&&
...
@@ -5795,6 +5919,108 @@ component_io_cb (GSocket *gsocket, GIOCondition condition, gpointer user_data)
...
@@ -5795,6 +5919,108 @@ component_io_cb (GSocket *gsocket, GIOCondition condition, gpointer user_data)
break
;
break
;
}
}
has_io_callback
=
nice_component_has_io_callback
(
component
);
}
}
else
if
(
agent
->
reliable
&&
nice_socket_is_reliable
(
socket_source
->
socket
))
{
NiceInputMessageIter
*
iter
=
&
component
->
recv_messages_iter
;
gsize
total_bytes_received
=
0
;
while
(
has_io_callback
||
(
component
->
recv_messages
!=
NULL
&&
!
nice_input_message_iter_is_at_end
(
iter
,
component
->
recv_messages
,
component
->
n_recv_messages
)))
{
GInputVector
internal_buf
=
{
component
->
recv_buffer
,
component
->
recv_buffer_size
};
NiceInputMessage
internal_message
=
{
&
internal_buf
,
1
,
NULL
,
0
};
NiceInputMessage
*
msg
;
guint
n_bufs
,
i
;
GInputVector
*
bufs
;
RecvStatus
retval
=
0
;
msg
=
has_io_callback
?
&
internal_message
:
&
component
->
recv_messages
[
iter
->
message
];
if
(
msg
->
n_buffers
==
-
1
)
{
n_bufs
=
0
;
for
(
i
=
0
;
msg
->
buffers
[
i
].
buffer
!=
NULL
;
i
++
)
n_bufs
++
;
}
else
{
n_bufs
=
msg
->
n_buffers
;
}
bufs
=
g_newa
(
GInputVector
,
n_bufs
);
memcpy
(
bufs
,
msg
->
buffers
,
n_bufs
*
sizeof
(
GInputVector
));
msg
->
length
=
0
;
do
{
NiceInputMessage
m
=
{
bufs
,
n_bufs
,
msg
->
from
,
0
};
gsize
off
;
retval
=
agent_recv_message_unlocked
(
agent
,
stream
,
component
,
socket_source
->
socket
,
&
m
);
if
(
retval
==
RECV_WOULD_BLOCK
||
retval
==
RECV_ERROR
)
break
;
if
(
retval
==
RECV_OOB
)
continue
;
msg
->
length
+=
m
.
length
;
total_bytes_received
+=
m
.
length
;
if
(
!
agent
->
bytestream_tcp
)
break
;
off
=
0
;
for
(
i
=
0
;
i
<
n_bufs
;
i
++
)
{
GInputVector
*
buf
=
&
bufs
[
i
];
const
gsize
start
=
off
;
const
gsize
end
=
start
+
buf
->
size
;
if
(
m
.
length
>
start
)
{
const
gsize
consumed
=
MIN
(
m
.
length
-
start
,
buf
->
size
);
buf
->
buffer
=
(
guint8
*
)
buf
->
buffer
+
consumed
;
buf
->
size
-=
consumed
;
if
(
buf
->
size
>
0
)
break
;
}
else
{
break
;
}
off
=
end
;
}
bufs
+=
i
;
n_bufs
-=
i
;
}
while
(
n_bufs
>
0
);
if
(
msg
->
length
>
0
)
{
nice_debug_verbose
(
"%s: %p: received a valid message with %"
G_GSIZE_FORMAT
" bytes"
,
G_STRFUNC
,
agent
,
msg
->
length
);
if
(
has_io_callback
)
{
nice_component_emit_io_callback
(
agent
,
component
,
msg
->
length
);
}
else
{
iter
->
message
++
;
}
}
if
(
retval
==
RECV_WOULD_BLOCK
)
{
/* EWOULDBLOCK. */
break
;
}
else
if
(
retval
==
RECV_ERROR
)
{
/* Other error. */
nice_debug
(
"%s: error receiving message"
,
G_STRFUNC
);
remove_source
=
TRUE
;
break
;
}
if
(
has_io_callback
&&
g_source_is_destroyed
(
g_main_current_source
()))
{
nice_debug
(
"Component IO source disappeared during the callback"
);
goto
out
;
}
has_io_callback
=
nice_component_has_io_callback
(
component
);
has_io_callback
=
nice_component_has_io_callback
(
component
);
}
}
}
else
if
(
has_io_callback
)
{
}
else
if
(
has_io_callback
)
{
...
...
agent/agent.h
View file @
a13ac437
...
@@ -409,6 +409,7 @@ typedef enum
...
@@ -409,6 +409,7 @@ typedef enum
* @NICE_AGENT_OPTION_SUPPORT_RENOMINATION: Enable renomination triggered by NOMINATION STUN attribute
* @NICE_AGENT_OPTION_SUPPORT_RENOMINATION: Enable renomination triggered by NOMINATION STUN attribute
* proposed here: https://tools.ietf.org/html/draft-thatcher-ice-renomination-00
* proposed here: https://tools.ietf.org/html/draft-thatcher-ice-renomination-00
* @NICE_AGENT_OPTION_CONSENT_FRESHNESS: Enable RFC 7675 consent freshness support. (Since: 0.1.19)
* @NICE_AGENT_OPTION_CONSENT_FRESHNESS: Enable RFC 7675 consent freshness support. (Since: 0.1.19)
* @NICE_AGENT_OPTION_BYTESTREAM_TCP: Use bytestream mode for reliable TCP connections. (Since: 0.1.20)
*
*
* These are options that can be passed to nice_agent_new_full(). They set
* These are options that can be passed to nice_agent_new_full(). They set
* various properties on the agent. Not including them sets the property to
* various properties on the agent. Not including them sets the property to
...
@@ -424,6 +425,7 @@ typedef enum {
...
@@ -424,6 +425,7 @@ typedef enum {
NICE_AGENT_OPTION_ICE_TRICKLE
=
1
<<
3
,
NICE_AGENT_OPTION_ICE_TRICKLE
=
1
<<
3
,
NICE_AGENT_OPTION_SUPPORT_RENOMINATION
=
1
<<
4
,
NICE_AGENT_OPTION_SUPPORT_RENOMINATION
=
1
<<
4
,
NICE_AGENT_OPTION_CONSENT_FRESHNESS
=
1
<<
5
,
NICE_AGENT_OPTION_CONSENT_FRESHNESS
=
1
<<
5
,
NICE_AGENT_OPTION_BYTESTREAM_TCP
=
1
<<
6
,
}
NiceAgentOption
;
}
NiceAgentOption
;
/**
/**
...
...
agent/component.c
View file @
a13ac437
...
@@ -388,6 +388,7 @@ nice_component_close (NiceAgent *agent, NiceStream *stream, NiceComponent *cmp)
...
@@ -388,6 +388,7 @@ nice_component_close (NiceAgent *agent, NiceStream *stream, NiceComponent *cmp)
}
}
g_free
(
cmp
->
recv_buffer
);
g_free
(
cmp
->
recv_buffer
);
g_free
(
cmp
->
rfc4571_buffer
);
}
}
/*
/*
...
@@ -1129,6 +1130,9 @@ nice_component_init (NiceComponent *component)
...
@@ -1129,6 +1130,9 @@ nice_component_init (NiceComponent *component)
component
->
recv_buffer
=
g_malloc
(
MAX_BUFFER_SIZE
);
component
->
recv_buffer
=
g_malloc
(
MAX_BUFFER_SIZE
);
component
->
recv_buffer_size
=
MAX_BUFFER_SIZE
;
component
->
recv_buffer_size
=
MAX_BUFFER_SIZE
;
component
->
rfc4571_buffer_size
=
sizeof
(
guint16
)
+
G_MAXUINT16
;
component
->
rfc4571_buffer
=
g_malloc
(
component
->
rfc4571_buffer_size
);
}
}
static
void
static
void
...
@@ -1304,6 +1308,9 @@ static gboolean
...
@@ -1304,6 +1308,9 @@ static gboolean
component_source_prepare
(
GSource
*
source
,
gint
*
timeout_
)
component_source_prepare
(
GSource
*
source
,
gint
*
timeout_
)
{
{
ComponentSource
*
component_source
=
(
ComponentSource
*
)
source
;
ComponentSource
*
component_source
=
(
ComponentSource
*
)
source
;
/* We can’t be sure if the ComponentSource itself needs to be dispatched until
* poll() is called on all the child sources. */
gboolean
skip_poll
=
FALSE
;
NiceAgent
*
agent
;
NiceAgent
*
agent
;
NiceComponent
*
component
;
NiceComponent
*
component
;
GSList
*
parentl
,
*
childl
;
GSList
*
parentl
,
*
childl
;
...
@@ -1320,6 +1327,11 @@ component_source_prepare (GSource *source, gint *timeout_)
...
@@ -1320,6 +1327,11 @@ component_source_prepare (GSource *source, gint *timeout_)
&
component
))
&
component
))
goto
done
;
goto
done
;
if
(
component
->
rfc4571_wakeup_needed
)
{
component
->
rfc4571_wakeup_needed
=
FALSE
;
skip_poll
=
TRUE
;
goto
done
;
}
if
(
component
->
socket_sources_age
==
if
(
component
->
socket_sources_age
==
component_source
->
component_socket_sources_age
)
component_source
->
component_socket_sources_age
)
...
@@ -1393,9 +1405,7 @@ component_source_prepare (GSource *source, gint *timeout_)
...
@@ -1393,9 +1405,7 @@ component_source_prepare (GSource *source, gint *timeout_)
agent_unlock_and_emit
(
agent
);
agent_unlock_and_emit
(
agent
);
g_object_unref
(
agent
);
g_object_unref
(
agent
);
/* We can’t be sure if the ComponentSource itself needs to be dispatched until
return
skip_poll
;
* poll() is called on all the child sources. */
return
FALSE
;
}
}
static
gboolean
static
gboolean
...
@@ -1659,3 +1669,9 @@ nice_component_get_sockets (NiceComponent *component)
...
@@ -1659,3 +1669,9 @@ nice_component_get_sockets (NiceComponent *component)
return
array
;
return
array
;
}
}
guint
nice_component_compute_rfc4571_headroom
(
NiceComponent
*
component
)
{
return
component
->
rfc4571_buffer_offset
-
component
->
rfc4571_frame_offset
;
}
agent/component.h
View file @
a13ac437
...
@@ -241,6 +241,16 @@ struct _NiceComponent {
...
@@ -241,6 +241,16 @@ struct _NiceComponent {
*/
*/
guint8
*
recv_buffer
;
guint8
*
recv_buffer
;
guint
recv_buffer_size
;
guint
recv_buffer_size
;
/* ICE-TCP frame state */
guint8
*
rfc4571_buffer
;
guint
rfc4571_buffer_offset
;
guint
rfc4571_buffer_size
;
guint
rfc4571_frame_offset
;
guint
rfc4571_frame_size
;
guint
rfc4571_consumed_size
;
NiceAddress
rfc4571_remote_addr
;
gboolean
rfc4571_wakeup_needed
;
};
};
typedef
struct
{
typedef
struct
{
...
@@ -331,6 +341,9 @@ nice_component_verify_remote_candidate (NiceComponent *component,
...
@@ -331,6 +341,9 @@ nice_component_verify_remote_candidate (NiceComponent *component,
GPtrArray
*
GPtrArray
*
nice_component_get_sockets
(
NiceComponent
*
component
);
nice_component_get_sockets
(
NiceComponent
*
component
);
guint
nice_component_compute_rfc4571_headroom
(
NiceComponent
*
component
);
G_END_DECLS
G_END_DECLS
#endif
/* _NICE_COMPONENT_H */
#endif
/* _NICE_COMPONENT_H */
...
...
tests/meson.build
View file @
a13ac437
...
@@ -23,6 +23,7 @@ nice_tests = [
...
@@ -23,6 +23,7 @@ nice_tests = [
'test-trickle',
'test-trickle',
'test-tcp',
'test-tcp',
'test-icetcp',
'test-icetcp',
'test-bytestream-tcp',
'test-credentials',
'test-credentials',
'test-turn',
'test-turn',
'test-drop-invalid',
'test-drop-invalid',
...
@@ -40,7 +41,7 @@ if cc.has_header('arpa/inet.h')
...
@@ -40,7 +41,7 @@ if cc.has_header('arpa/inet.h')
endif
endif
foreach tname : nice_tests
foreach tname : nice_tests
if tname.startswith('test-io-stream') or tname.startswith('test-send-recv')
if tname.startswith('test-io-stream') or tname.startswith('test-send-recv')
or tname == 'test-bytestream-tcp'
extra_src = ['test-io-stream-common.c']
extra_src = ['test-io-stream-common.c']
else
else
extra_src = []
extra_src = []
...
...
tests/test-bytestream-tcp.c
0 → 100644
View file @
a13ac437
/*
* This file is part of the Nice GLib ICE library.
*
* (C) 2013 Collabora Ltd.
* Contact: Philip Withnall
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Nice GLib ICE library.
*
* The Initial Developers of the Original Code are Collabora Ltd and Nokia
* Corporation. All Rights Reserved.
*
* Contributors:
* Philip Withnall, Collabora Ltd.
*
* Alternatively, the contents of this file may be used under the terms of the
* the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
* case the provisions of LGPL are applicable instead of those above. If you
* wish to allow use of your version of this file only under the terms of the
* LGPL and not to allow others to use your version of this file under the
* MPL, indicate your decision by deleting the provisions above and replace
* them with the notice and other provisions required by the LGPL. If you do
* not delete the provisions above, a recipient may use your version of this
* file under either the MPL or the LGPL.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "agent.h"
#include "test-io-stream-common.h"
#include <stdlib.h>
#include <string.h>
#ifndef G_OS_WIN32
#include <unistd.h>
#endif
typedef
struct
{
gsize
recv_count
;
gsize
*
other_recv_count
;
gsize
send_count
;
gsize
*
other_send_count
;
}
ThreadData
;
static
const
gchar
test_sequence
[]
=
{
'1'
,
'2'
,
'3'
,
'4'
};
static
void
read_thread_cb
(
GInputStream
*
input_stream
,
TestIOStreamThreadData
*
data
)
{
ThreadData
*
user_data
=
data
->
user_data
;
guint8
buf
[
2
];
GError
*
error
=
NULL
;
g_input_stream_read_all
(
input_stream
,
buf
,
sizeof
(
buf
),
NULL
,
NULL
,
&
error
);
g_assert_no_error
(
error
);
user_data
->
recv_count
++
;
g_assert_cmpmem
(
buf
,
sizeof
(
buf
),
test_sequence
,
sizeof
(
buf
));
g_input_stream_read_all
(
input_stream
,
buf
,
sizeof
(
buf
),
NULL
,
NULL
,
&
error
);
g_assert_no_error
(
error
);
user_data
->
recv_count
++
;
g_assert_cmpmem
(
buf
,
sizeof
(
buf
),
test_sequence
+
2
,
sizeof
(
buf
));
check_for_termination
(
data
,
&
user_data
->
recv_count
,
user_data
->
other_recv_count
,
&
user_data
->
send_count
,
2
);
}
static
void
write_thread_cb
(
GOutputStream
*
output_stream
,
TestIOStreamThreadData
*
data
)
{
ThreadData
*
user_data
=
data
->
user_data
;
GError
*
error
=
NULL
;
g_output_stream_write_all
(
output_stream
,
test_sequence
,
sizeof
(
test_sequence
),
NULL
,
NULL
,
&
error
);
g_assert_no_error
(
error
);
user_data
->
send_count
+=
2
;
}
int
main
(
void
)
{
ThreadData
*
l_data
,
*
r_data
;
const
TestIOStreamCallbacks
callbacks
=
{
read_thread_cb
,
write_thread_cb
,
NULL
,
NULL
,
};
#ifdef G_OS_WIN32
WSADATA
w
;
WSAStartup
(
0x0202
,
&
w
);
#endif
l_data
=
g_malloc0
(
sizeof
(
ThreadData
));
r_data
=
g_malloc0
(
sizeof
(
ThreadData
));
l_data
->
recv_count
=
0
;
l_data
->
other_recv_count
=
&
r_data
->
recv_count
;
l_data
->
send_count
=
0
;
l_data
->
other_send_count
=
&
r_data
->
send_count
;
r_data
->
recv_count
=
0
;
r_data
->
other_recv_count
=
&
l_data
->
recv_count
;
r_data
->
send_count
=
0
;
r_data
->
other_send_count
=
&
l_data
->
send_count
;
run_io_stream_test
(
30
,
TRUE
,
&
callbacks
,
l_data
,
NULL
,
r_data
,
NULL
,
TEST_IO_STREAM_OPTION_TCP_ONLY
|
TEST_IO_STREAM_OPTION_BYTESTREAM_TCP
);
g_free
(
r_data
);
g_free
(
l_data
);
#ifdef G_OS_WIN32
WSACleanup
();
#endif
return
0
;
}
tests/test-io-stream-cancelling.c
View file @
a13ac437
...
@@ -128,7 +128,7 @@ int main (void)
...
@@ -128,7 +128,7 @@ int main (void)
r_cancellation_thread
=
spawn_thread
(
"libnice R cancel"
,
r_cancellation_thread
=
spawn_thread
(
"libnice R cancel"
,
cancellation_thread_cb
,
&
r_data
);
cancellation_thread_cb
,
&
r_data
);
run_io_stream_test
(
30
,
TRUE
,
&
callbacks
,
&
l_data
,
NULL
,
&
r_data
,
NULL
);
run_io_stream_test
(
30
,
TRUE
,
&
callbacks
,
&
l_data
,
NULL
,
&
r_data
,
NULL
,
0
);
g_thread_join
(
l_cancellation_thread
);
g_thread_join
(
l_cancellation_thread
);
g_thread_join
(
r_cancellation_thread
);
g_thread_join
(
r_cancellation_thread
);
...
...
tests/test-io-stream-closing-read.c
View file @
a13ac437
...
@@ -128,7 +128,8 @@ int main (void)
...
@@ -128,7 +128,8 @@ int main (void)
WSAStartup
(
0x0202
,
&
w
);
WSAStartup
(
0x0202
,
&
w
);
#endif
#endif
run_io_stream_test
(
30
,
TRUE
,
&
callbacks
,
(
gpointer
)
TRUE
,
NULL
,
NULL
,
NULL
);
run_io_stream_test
(
30
,
TRUE
,
&
callbacks
,
(
gpointer
)
TRUE
,
NULL
,
NULL
,
NULL
,
0
);
#ifdef G_OS_WIN32
#ifdef G_OS_WIN32
WSACleanup
();
WSACleanup
();
...
...
tests/test-io-stream-closing-write.c
View file @
a13ac437
...
@@ -128,7 +128,8 @@ int main (void)
...
@@ -128,7 +128,8 @@ int main (void)
WSAStartup
(
0x0202
,
&
w
);
WSAStartup
(
0x0202
,
&
w
);
#endif
#endif
run_io_stream_test
(
30
,
TRUE
,
&
callbacks
,
(
gpointer
)
TRUE
,
NULL
,
NULL
,
NULL
);
run_io_stream_test
(
30
,
TRUE
,
&
callbacks
,
(
gpointer
)
TRUE
,
NULL
,
NULL
,
NULL
,
0
);
#ifdef G_OS_WIN32
#ifdef G_OS_WIN32
WSACleanup
();
WSACleanup
();
...
...
tests/test-io-stream-common.c
View file @
a13ac437
...
@@ -243,7 +243,8 @@ new_selected_pair_cb (NiceAgent *agent, guint stream_id, guint component_id,
...
@@ -243,7 +243,8 @@ new_selected_pair_cb (NiceAgent *agent, guint stream_id, guint component_id,
static
NiceAgent
*
static
NiceAgent
*
create_agent
(
gboolean
controlling_mode
,
TestIOStreamThreadData
*
data
,
create_agent
(
gboolean
controlling_mode
,
TestIOStreamThreadData
*
data
,
GMainContext
**
main_context
,
GMainLoop
**
main_loop
)
GMainContext
**
main_context
,
GMainLoop
**
main_loop
,
TestIOStreamOption
flags
)
{
{
NiceAgent
*
agent
;
NiceAgent
*
agent
;
NiceAddress
base_addr
;
NiceAddress
base_addr
;
...
@@ -253,17 +254,29 @@ create_agent (gboolean controlling_mode, TestIOStreamThreadData *data,
...
@@ -253,17 +254,29 @@ create_agent (gboolean controlling_mode, TestIOStreamThreadData *data,
*
main_context
=
g_main_context_new
();
*
main_context
=
g_main_context_new
();
*
main_loop
=
g_main_loop_new
(
*
main_context
,
FALSE
);
*
main_loop
=
g_main_loop_new
(
*
main_context
,
FALSE
);
/* Use Google compatibility to ignore credentials. */
if
(
data
->
reliable
)
if
(
data
->
reliable
)
agent
=
nice_agent_new_reliable
(
*
main_context
,
NICE_COMPATIBILITY_
GOOGLE
);
agent
=
nice_agent_new_reliable
(
*
main_context
,
NICE_COMPATIBILITY_
RFC5245
);
else
else
agent
=
nice_agent_new
(
*
main_context
,
NICE_COMPATIBILITY_
GOOGLE
);
agent
=
nice_agent_new
(
*
main_context
,
NICE_COMPATIBILITY_
RFC5245
);
g_object_set
(
G_OBJECT
(
agent
),
g_object_set
(
G_OBJECT
(
agent
),
"controlling-mode"
,
controlling_mode
,
"controlling-mode"
,
controlling_mode
,
"upnp"
,
FALSE
,
"upnp"
,
FALSE
,
NULL
);
NULL
);
if
(
flags
&
TEST_IO_STREAM_OPTION_TCP_ONLY
)
{
g_object_set
(
G_OBJECT
(
agent
),
"ice-udp"
,
FALSE
,
"ice-tcp"
,
TRUE
,
NULL
);
}
if
(
flags
&
TEST_IO_STREAM_OPTION_BYTESTREAM_TCP
)
{
g_object_set
(
G_OBJECT
(
agent
),
"bytestream-tcp"
,
TRUE
,
NULL
);
}
/* Specify which local interface to use. */
/* Specify which local interface to use. */
g_assert_true
(
nice_address_set_from_string
(
&
base_addr
,
"127.0.0.1"
));
g_assert_true
(
nice_address_set_from_string
(
&
base_addr
,
"127.0.0.1"
));
nice_agent_add_local_address
(
agent
,
&
base_addr
);
nice_agent_add_local_address
(
agent
,
&
base_addr
);
...
@@ -310,6 +323,28 @@ add_stream (NiceAgent *agent)
...
@@ -310,6 +323,28 @@ add_stream (NiceAgent *agent)
GUINT_TO_POINTER
(
stream_id
));
GUINT_TO_POINTER
(
stream_id
));
}
}
static
void
swap_credentials
(
NiceAgent
*
agent
)
{
guint
stream_id
;
gchar
*
ufrag
,
*
password
;
NiceAgent
*
other_agent
;
guint
other_stream_id
;
stream_id
=
GPOINTER_TO_UINT
(
g_object_get_data
(
G_OBJECT
(
agent
),
"stream-id"
));
nice_agent_get_local_credentials
(
agent
,
stream_id
,
&
ufrag
,
&
password
);
other_agent
=
g_object_get_data
(
G_OBJECT
(
agent
),
"other-agent"
);
other_stream_id
=
GPOINTER_TO_UINT
(
g_object_get_data
(
G_OBJECT
(
other_agent
),
"stream-id"
));
nice_agent_set_remote_credentials
(
other_agent
,
other_stream_id
,
ufrag
,
password
);
g_free
(
ufrag
);
g_free
(
password
);
}
static
void
static
void
run_agent
(
TestIOStreamThreadData
*
data
,
NiceAgent
*
agent
)
run_agent
(
TestIOStreamThreadData
*
data
,
NiceAgent
*
agent
)
{
{
...
@@ -346,7 +381,8 @@ void
...
@@ -346,7 +381,8 @@ void
run_io_stream_test
(
guint
deadlock_timeout
,
gboolean
reliable
,
run_io_stream_test
(
guint
deadlock_timeout
,
gboolean
reliable
,
const
TestIOStreamCallbacks
*
callbacks
,
const
TestIOStreamCallbacks
*
callbacks
,
gpointer
l_user_data
,
GDestroyNotify
l_user_data_free
,
gpointer
l_user_data
,
GDestroyNotify
l_user_data_free
,
gpointer
r_user_data
,
GDestroyNotify
r_user_data_free
)
gpointer
r_user_data
,
GDestroyNotify
r_user_data_free
,
TestIOStreamOption
flags
)
{
{
GMainLoop
*
error_loop
;
GMainLoop
*
error_loop
;
GThread
*
l_main_thread
,
*
r_main_thread
;
GThread
*
l_main_thread
,
*
r_main_thread
;
...
@@ -396,9 +432,9 @@ run_io_stream_test (guint deadlock_timeout, gboolean reliable,
...
@@ -396,9 +432,9 @@ run_io_stream_test (guint deadlock_timeout, gboolean reliable,
/* Create the L and R agents. */
/* Create the L and R agents. */
l_data
.
agent
=
create_agent
(
TRUE
,
&
l_data
,
l_data
.
agent
=
create_agent
(
TRUE
,
&
l_data
,
&
l_data
.
main_context
,
&
l_data
.
main_loop
);
&
l_data
.
main_context
,
&
l_data
.
main_loop
,
flags
);
r_data
.
agent
=
create_agent
(
FALSE
,
&
r_data
,
r_data
.
agent
=
create_agent
(
FALSE
,
&
r_data
,
&
r_data
.
main_context
,
&
r_data
.
main_loop
);
&
r_data
.
main_context
,
&
r_data
.
main_loop
,
flags
);
g_object_set_data
(
G_OBJECT
(
l_data
.
agent
),
"other-agent"
,
r_data
.
agent
);
g_object_set_data
(
G_OBJECT
(
l_data
.
agent
),
"other-agent"
,
r_data
.
agent
);
g_object_set_data
(
G_OBJECT
(
r_data
.
agent
),
"other-agent"
,
l_data
.
agent
);
g_object_set_data
(
G_OBJECT
(
r_data
.
agent
),
"other-agent"
,
l_data
.
agent
);
...
@@ -411,6 +447,8 @@ run_io_stream_test (guint deadlock_timeout, gboolean reliable,
...
@@ -411,6 +447,8 @@ run_io_stream_test (guint deadlock_timeout, gboolean reliable,
add_stream
(
l_data
.
agent
);
add_stream
(
l_data
.
agent
);
add_stream
(
r_data
.
agent
);
add_stream
(
r_data
.
agent
);
swap_credentials
(
l_data
.
agent
);
swap_credentials
(
r_data
.
agent
);
run_agent
(
&
l_data
,
l_data
.
agent
);
run_agent
(
&
l_data
,
l_data
.
agent
);
run_agent
(
&
r_data
,
r_data
.
agent
);
run_agent
(
&
r_data
,
r_data
.
agent
);
...
...
tests/test-io-stream-common.h
View file @
a13ac437
...
@@ -105,12 +105,19 @@ struct _TestIOStreamThreadData {
...
@@ -105,12 +105,19 @@ struct _TestIOStreamThreadData {
guint
*
start_count
;
guint
*
start_count
;
};
};
typedef
enum
{
TEST_IO_STREAM_OPTION_TCP_ONLY
=
1
<<
0
,
TEST_IO_STREAM_OPTION_BYTESTREAM_TCP
=
1
<<
1
,
}
TestIOStreamOption
;
GThread
*
spawn_thread
(
const
gchar
*
thread_name
,
GThreadFunc
thread_func
,
GThread
*
spawn_thread
(
const
gchar
*
thread_name
,
GThreadFunc
thread_func
,
gpointer
user_data
);
gpointer
user_data
);
void
run_io_stream_test
(
guint
deadlock_timeout
,
gboolean
reliable
,
void
run_io_stream_test
(
guint
deadlock_timeout
,
gboolean
reliable
,
const
TestIOStreamCallbacks
*
callbacks
,
const
TestIOStreamCallbacks
*
callbacks
,
gpointer
l_user_data
,
GDestroyNotify
l_user_data_free
,
gpointer
l_user_data
,
GDestroyNotify
l_user_data_free
,
gpointer
r_user_data
,
GDestroyNotify
r_user_data_free
);
gpointer
r_user_data
,
GDestroyNotify
r_user_data_free
,
TestIOStreamOption
flags
);
void
check_for_termination
(
TestIOStreamThreadData
*
data
,
gsize
*
recv_count
,
void
check_for_termination
(
TestIOStreamThreadData
*
data
,
gsize
*
recv_count
,
gsize
*
other_recv_count
,
volatile
gsize
*
send_count
,
gsize
expected_recv_count
);
gsize
*
other_recv_count
,
volatile
gsize
*
send_count
,
gsize
expected_recv_count
);
...
...
tests/test-io-stream-pollable.c
View file @
a13ac437
...
@@ -178,7 +178,7 @@ int main (void)
...
@@ -178,7 +178,7 @@ int main (void)
r_data
->
other_send_count
=
&
l_data
->
send_count
;
r_data
->
other_send_count
=
&
l_data
->
send_count
;
r_data
->
recv_offset
=
0
;
r_data
->
recv_offset
=
0
;
run_io_stream_test
(
30
,
TRUE
,
&
callbacks
,
l_data
,
NULL
,
r_data
,
NULL
);
run_io_stream_test
(
30
,
TRUE
,
&
callbacks
,
l_data
,
NULL
,
r_data
,
NULL
,
0
);
g_free
(
r_data
);
g_free
(
r_data
);
g_free
(
l_data
);
g_free
(
l_data
);
...
...
tests/test-io-stream-thread.c
View file @
a13ac437
...
@@ -143,7 +143,7 @@ int main (void)
...
@@ -143,7 +143,7 @@ int main (void)
r_data
->
send_count
=
0
;
r_data
->
send_count
=
0
;
r_data
->
other_send_count
=
&
l_data
->
send_count
;
r_data
->
other_send_count
=
&
l_data
->
send_count
;
run_io_stream_test
(
30
,
TRUE
,
&
callbacks
,
l_data
,
NULL
,
r_data
,
NULL
);
run_io_stream_test
(
30
,
TRUE
,
&
callbacks
,
l_data
,
NULL
,
r_data
,
NULL
,
0
);
/* Verify that correct number of local candidates were reported. */
/* Verify that correct number of local candidates were reported. */
g_assert_cmpuint
(
l_data
->
cand_count
,
==
,
1
);
g_assert_cmpuint
(
l_data
->
cand_count
,
==
,
1
);
...
...
tests/test-send-recv.c
View file @
a13ac437
...
@@ -1146,7 +1146,9 @@ test (gboolean reliable, StreamApi stream_api, gsize n_bytes, guint n_messages,
...
@@ -1146,7 +1146,9 @@ test (gboolean reliable, StreamApi stream_api, gsize n_bytes, guint n_messages,
&
l_data
.
received_bytes
,
&
l_data
.
received_messages
);
&
l_data
.
received_bytes
,
&
l_data
.
received_messages
);
run_io_stream_test
(
deadlock_timeout
,
reliable
,
&
callbacks
[
stream_api
],
run_io_stream_test
(
deadlock_timeout
,
reliable
,
&
callbacks
[
stream_api
],
&
l_data
,
NULL
,
&
r_data
,
NULL
);
&
l_data
,
NULL
,
&
r_data
,
NULL
,
/* Ensure TCP has the same behavior as Pseudo-TCP in reliable mode: */
reliable
?
TEST_IO_STREAM_OPTION_BYTESTREAM_TCP
:
0
);
test_data_clear
(
&
r_data
);
test_data_clear
(
&
r_data
);
test_data_clear
(
&
l_data
);
test_data_clear
(
&
l_data
);
...
...
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