10772 lines
384 KiB
Diff
10772 lines
384 KiB
Diff
commit 30a0c230ae9b70c572060ad3037f68e102e4759a
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Mon Jun 6 18:31:22 2016 -0400
|
||
|
||
conncheck: Remove pairs before freeing candidate
|
||
|
||
Remove the whole pair before the candidate is
|
||
to be freed.
|
||
|
||
https://phabricator.freedesktop.org/T7460
|
||
|
||
commit 71f7ed3eda829c3dc6afe9ed013c0ab826a1aa40
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Fri Feb 19 15:01:03 2016 -0500
|
||
|
||
stun timer: Do 7 retransmissions as recommended
|
||
|
||
Also reduce the normal timeout to make the test bearable.
|
||
|
||
This is what RFC 5389 section 7.2.1
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D1056
|
||
Maniphest Task: https://phabricator.freedesktop.org/T3339
|
||
|
||
commit dc1e1b7a1b258fb54ba582d2fe77ccd159c9fe88
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Mon Jun 6 16:21:54 2016 -0400
|
||
|
||
timer: Maximum retransmission should include the original one
|
||
|
||
We really care about the maximum transmissions, the first one counts.
|
||
|
||
commit fad72879fa4a0896c55ac6fc5f77f6c05e369a2b
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Fri Jun 3 18:42:59 2016 -0400
|
||
|
||
pseudotcp: it's still a GObject
|
||
|
||
commit f645ea6b11c167b1d7f4c5034f79664bdb8706d6
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Thu Apr 14 13:32:51 2016 +0200
|
||
|
||
pseudotcp: Make sure duplicate ack representing losses have no data
|
||
|
||
If they have data in them, they won't be recognized as duplicate acks by
|
||
the sender.
|
||
|
||
commit adba0d4a51f4e0deac888ab08f7976cef70a8e99
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Thu Apr 14 09:50:09 2016 +0200
|
||
|
||
pseudotcp: Implement NewReno timestamp heuristic
|
||
|
||
This allows the sender to enter fast retransmit after a timeout because
|
||
it can now detect that three duplicate acks are caused by a packet loss.
|
||
|
||
As specific in RFC 6582 section 4.2.
|
||
|
||
commit 1f532aeb6bf5b5b3042c445e677988f3327b1cb5
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Wed Apr 6 10:46:46 2016 +0300
|
||
|
||
pseudotcp: Set min RTO to 1 second
|
||
|
||
This is recommended by RFC 6298
|
||
|
||
commit b5952012bc5b403550f8dd9945d92747323acfc4
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Wed Apr 6 01:59:36 2016 +0300
|
||
|
||
pseudotcp: Implement full NewReno
|
||
|
||
commit e31932bdf25ce545a88fe6078b9557bc4d9e6365
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Tue Feb 2 16:59:18 2016 -0500
|
||
|
||
pseudotcp: Make debug more useful
|
||
|
||
commit 8ccb2c1711a2e5cdebf9411764fd92d5a089ffbf
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Tue Jan 12 20:14:48 2016 -0500
|
||
|
||
pseudotcp: Separate default and maximum MTU
|
||
|
||
Accept packets much beyond the default MTU, but
|
||
set a reasonable default MTU for sending of 1400
|
||
|
||
commit cb644b2baa681f510a79e158cd50c490dcfa5186
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Thu Dec 24 01:15:59 2015 -0500
|
||
|
||
pseudotcp: close local socket on initial transmission error
|
||
|
||
This is required as no retransmissions will happen
|
||
|
||
commit 23331ff2add5a60d611eee2093614d1fb8749164
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Thu Sep 17 21:26:36 2015 -0400
|
||
|
||
pseudotcp: Export more symbols for PseudoTCP
|
||
|
||
commit 026c15a838554c30ea96a59b08a2064b61d62736
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Thu Sep 17 15:00:27 2015 -0400
|
||
|
||
pseudotcp: Make structs definitions private
|
||
|
||
commit 11d4bb9783a69363de80ff49638030ba892a93fe
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Tue Jun 23 15:42:33 2015 +0100
|
||
|
||
pseudotcp: Correct behaviour of buffer size methods when part-closed
|
||
|
||
Correct the behaviour of pseudo_tcp_socket_get_available_bytes() and
|
||
pseudo_tcp_get_available_send_space() when the socket is not in
|
||
TCP_ESTABLISHED state. It’s still permissible to send and receive up
|
||
until the local side calls pseudo_tcp_socket_close(), which means we
|
||
may be in state TCP_ESTABLISHED *or TCP_CLOSE_WAIT*.
|
||
|
||
commit a9a149f529b3165543b52260d40a7855401841da
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Fri Jul 31 14:28:51 2015 +0100
|
||
|
||
pseudotcp: Fix EOS checks in high packet loss situations
|
||
|
||
The state tracking previously assumed that if a FIN packet was sent, the
|
||
other side received it and the preceding packets, and hence it was
|
||
correct to sent an RST if an unexpected packet (such as a delayed
|
||
SYN-ACK) was received.
|
||
|
||
In cases where there is high packet loss, this won’t work. For example,
|
||
peer A sends a SYN, it is received and peer B replies with a SYN-ACK
|
||
which is also received; then peer A sends its data and a FIN, which are
|
||
both dropped. Since it hasn’t received anything since the original SYN,
|
||
peer B resends its SYN-ACK. If that is received, peer A was incorrectly
|
||
treating it as an erroneous packet, and would then send a RST. In actual
|
||
fact, it should take this as a signal that the data and FIN packets were
|
||
dropped, and should resend them.
|
||
|
||
TODO: Add unit tests
|
||
|
||
commit 4dc2b5d9a01e3314d229fb9aa80884d84c45c1f0
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Fri Jul 31 14:19:30 2015 +0100
|
||
|
||
pseudotcp: Propagate error codes from transmit() to callers
|
||
|
||
Otherwise we can’t easily differentiate between different transmission
|
||
failures; for example: underlying socket failures, versus retransmission
|
||
timeouts.
|
||
|
||
commit 8a6bc000a5d7395bd9c4ff9942be26bd4f7d2e44
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Tue Jun 23 15:40:13 2015 +0100
|
||
|
||
pseudotcp: Add more debug info on closing down a pseudo-TCP socket
|
||
|
||
commit a72a93e51dba5d239e0607380bb4799cf1b0caca
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Jun 24 14:06:05 2015 +0100
|
||
|
||
pseudotcp: Fix pseudo_tcp_socket_recv() in state TCP_CLOSE_WAIT
|
||
|
||
Previously, pseudo_tcp_socket_recv() would start returning 0 (EOS) as
|
||
soon as a FIN segment was received from the peer, even if there was
|
||
unread data already in the receive buffer.
|
||
|
||
Instead, the unread data should all be accessible before
|
||
pseudo_tcp_socket_recv() starts returning 0.
|
||
|
||
commit 02699917641922c9f1d337e3102f13a1ea1d83c4
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Jun 24 13:52:16 2015 +0100
|
||
|
||
pseudotcp: Fix retransmission of segments before handling a FIN
|
||
|
||
Previously, if peer A transmitted one or more data segments (1),
|
||
followed by a FIN segment (2) to peer B, and segments 1 were
|
||
dropped, peer B would not request retransmission of them and would
|
||
instead continue with the FIN handshake. This effectively meant
|
||
segments 1 were lost without peer B realising.
|
||
|
||
Fix this by only handling the FIN segment once its sequence number is
|
||
acknowledged in the receive window.
|
||
|
||
commit b58e852de6183f2bda4e7d322a35d18edf5cbbed
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Thu Jun 2 19:22:50 2016 -0400
|
||
|
||
socket: Assert trying to use free'd socket
|
||
|
||
Cleanly returnign makes no sense and may hide
|
||
worse problems.
|
||
|
||
commit baab2c3c7049f984cdca6ed622059c62ce8cebf7
|
||
Author: Misha Uliutin <mishau@microsoft.com>
|
||
Date: Mon Apr 25 09:59:48 2016 +0300
|
||
|
||
component: Fix set TCP selected remote candidate
|
||
|
||
https://phabricator.freedesktop.org/T7407
|
||
|
||
commit 6329509b86f3a6877a39fb59b7a1b535408db0ce
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Thu Jun 2 19:00:17 2016 -0400
|
||
|
||
agent: Parse TURN packet on the right socket
|
||
|
||
https://phabricator.freedesktop.org/T99
|
||
|
||
commit 2f0daa030a69ebb2dea4c1a6fc47699d0f6828aa
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Thu Jun 2 17:34:27 2016 -0400
|
||
|
||
tests: Add TURN test
|
||
|
||
This test depends on rfc5766-turn-server which must
|
||
be installed for this test to run.
|
||
|
||
commit 75d332cc4b7d9ee76bdf92b38f9cc3f6dd94b796
|
||
Author: Jakub Adam <jakub.adam@ktknet.cz>
|
||
Date: Tue May 31 11:42:44 2016 +0000
|
||
|
||
conncheck: mark discovered pairs with TCP passive as valid
|
||
|
||
Doing so similarly to priv_process_response_check_for_reflexive(),
|
||
which also sets valid flag on discovered peer reflexive pairs.
|
||
|
||
Fixes a regression in previously working scenario.
|
||
Differential Revision: https://phabricator.freedesktop.org/D1035
|
||
|
||
commit 1a23476513d487bb09afbc7fb4853169399312d7
|
||
Author: Jakub Adam <jakub.adam@ktknet.cz>
|
||
Date: Wed Jun 1 08:52:41 2016 +0000
|
||
|
||
test-icetcp: don't be sensitive to the signal order
|
||
|
||
"new-selected-pair" may be emitted after "component-state-changed"
|
||
to READY, by which time the main loop might have gotten quit in
|
||
cb_component_state_changed(). Consequently, cb_new_selected_pair() could
|
||
miss to register the selected pair, ultimately leading to an assertion
|
||
failure in main().
|
||
|
||
We should wait for both selected pair and state change events to occur
|
||
before stopping the main loop.
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D1044
|
||
|
||
commit b559384734deb9ec934f5ff69814f3d90c6a36c1
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Tue May 31 17:31:18 2016 -0400
|
||
|
||
Revert "WIP"
|
||
|
||
This reverts commit 01519677ba4d8df46e2c07bc20a5ef03ee2d9c3a.
|
||
|
||
commit 01519677ba4d8df46e2c07bc20a5ef03ee2d9c3a
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Tue May 31 17:31:12 2016 -0400
|
||
|
||
WIP
|
||
|
||
commit 955323915c43b1a066399e61d0ab091f0b1d112b
|
||
Author: Jakub Adam <jakub.adam@ktknet.cz>
|
||
Date: Tue May 31 09:27:03 2016 +0000
|
||
|
||
conncheck: fix pruning conn checks with TCP active sockets
|
||
|
||
TCP active socket makes a NiceSocket for each peer in conn_check_send()
|
||
and this new socket is then stored as CandidateCheckPair's 'sockptr'.
|
||
We thus have to look also at the 'sockptr' value when eliminating
|
||
sockets which have received HUP from connection checks.
|
||
Differential Revision: https://phabricator.freedesktop.org/D1034
|
||
|
||
commit 2112ebba886d15fd96cc36b9fe3196834acaa892
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Tue Mar 8 15:37:05 2016 -0500
|
||
|
||
agent: Remove socket on read error
|
||
|
||
If a socket returned an error, remove it.
|
||
|
||
commit 1949b89f3de6e45616187e86f542d26a003ea7a6
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Fri Jan 15 22:40:27 2016 -0500
|
||
|
||
component: Add API to cleanly remove a base socket
|
||
|
||
commit 93330f1f97e4f2a9ff09b602765e620cb279574b
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Sat Feb 27 03:35:27 2016 -0500
|
||
|
||
agent: Fix udp-turn-over-tcp
|
||
|
||
The TCP-based turns don't come pre-parsed unlike
|
||
the UDP variants!
|
||
|
||
commit 7f6ddac880ee07530ae59f4c64a0a17417fb9e24
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Wed Jan 27 18:56:13 2016 -0500
|
||
|
||
agent: Add force-relay property to force messages through the relay
|
||
|
||
This allows implementing WebRTC privacy mode.
|
||
|
||
commit c69d479edfaeb461ff2bc61cf7257ce0c2d273da
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Wed Feb 10 16:29:57 2016 -0500
|
||
|
||
conncheck: Start conncheck on server reply if needed
|
||
|
||
This only really applies in the force relay mode where there are
|
||
no local candidates.
|
||
|
||
commit 1513ce23ff4279dad16e177a3fc779cb61074fa1
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Mon Feb 8 16:44:47 2016 -0500
|
||
|
||
Replace g_malloc/g_new with g_alloca where possible
|
||
|
||
This should reduce the overhead a bit.
|
||
|
||
commit 524c1090cc2813bcb1be6f7f29a894c742a608f7
|
||
Author: Fabrice Bellet <fabrice@bellet.info>
|
||
Date: Wed Apr 20 10:17:05 2016 +0000
|
||
|
||
conncheck: explain some corner cases
|
||
|
||
This patch give details why some exceptions to the ICE spec are needed.
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D876
|
||
|
||
commit b05debeb95c13d162286c0a5c4076eee2ae7cf51
|
||
Author: Fabrice Bellet <fabrice@bellet.info>
|
||
Date: Fri May 27 19:15:39 2016 -0400
|
||
|
||
conncheck: add a debug dump of the whole stream check list
|
||
|
||
https://phabricator.freedesktop.org/D814
|
||
|
||
commit 71e271095032bd50ac2be2b5d60f4beb15801fa0
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Fri May 27 18:50:59 2016 -0400
|
||
|
||
conncheck: fix the replay of early incoming connchecks
|
||
|
||
This patch fixes a bug in the way the list of incoming checks
|
||
is handled. The code purges this list too early, before all ichecks
|
||
for a given component are processed. It happens because the component
|
||
is computed from each pair of the check list, instead of being passed
|
||
as a fixed parameter of the function.
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D882
|
||
|
||
commit acdc0b8bb3cd2d48afe82c8dd8396a3c245191d9
|
||
Author: Fabrice Bellet <fabrice@bellet.info>
|
||
Date: Wed Apr 20 09:23:14 2016 +0000
|
||
|
||
stun: fix ice role conflict handling
|
||
|
||
This patch fixes the role conflict handling in stun ICE usage,
|
||
according to RFC 5245, by adding including missing cases in the
|
||
test. The role switch not only depends of the comparison of the
|
||
stun ice-controlling/controlled attrib with the agent tie breaker
|
||
value, but it also depends on the current role of the agent.
|
||
|
||
This patch also changes the value returned by
|
||
stun_usage_ice_conncheck_create_reply() when a role conflict exists
|
||
but doesn't change the role of the agent, causing an error stun
|
||
response. Previously, this case could not be differenciated by the
|
||
caller from a case with no role conflict. Now by examinating the
|
||
return value, and whether the control param changed, the caller
|
||
can check the four possibles situations. The stun test suite is
|
||
updated to match this change.
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D873
|
||
|
||
commit c90f93838db6a315ab2cbedaa92fed3f277b2103
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Fri May 27 17:26:06 2016 -0400
|
||
|
||
conncheck: Make previous commit compile
|
||
|
||
https://phabricator.freedesktop.org/T3324
|
||
|
||
commit d252feb553a423ee81482ff6b87e0033d9c046a6
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Mon Feb 8 18:49:42 2016 -0500
|
||
|
||
discovery: Make sure each candidate has a unique priority
|
||
|
||
This should fix compliance with RFC 5245 Section 4.1.2
|
||
|
||
https://phabricator.freedesktop.org/T3324
|
||
|
||
commit b72b9153d91a93a550c4ec40fce5f9a18e7eaac6
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Sun Sep 20 16:53:26 2015 -0400
|
||
|
||
agent: Restrict transitions to gathering
|
||
|
||
Only allow transitions to gathering from disconnected or
|
||
failed states.
|
||
|
||
commit 059a0e33c973a54c44f7c4fd1e766155f6078f80
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Fri May 27 14:06:24 2016 -0400
|
||
|
||
conncheck: fix TCP active relay handling
|
||
|
||
TCP active relay candidates use UDP TURN for their underlying socket.
|
||
Since 0a6c779f1f, socket->fileno of UDP TURN sockets is always NULL,
|
||
which caused a wrong code path to be chosen in conn_check_send().
|
||
|
||
We have to update the if-expression accordingly.
|
||
|
||
Maniphest Tasks: T7442
|
||
Differential Revision: https://phabricator.freedesktop.org/D1017
|
||
|
||
commit fc4d3aab5392f855dbda7ad0225bf0ad4e5fafb6
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Fri May 27 11:29:22 2016 -0400
|
||
|
||
agent: ignore gathering failures on auto-generated IPs
|
||
|
||
Candidate gathering is stopped when discovery_add_local_host_candidate()
|
||
returns HOST_CANDIDATE_CANT_CREATE_SOCKET. This may be too radical
|
||
a measure when other local addresses can still be able to generate
|
||
usable candidates.
|
||
|
||
The issue was observed by a user who had an IPv6 address with tentative
|
||
flag on one of the interfaces. That single failing address was causing
|
||
the whole gathering process to end with no candidates found.
|
||
|
||
Still, don't do this if nice_agent_add_local_address() has been called.
|
||
In that case, the user really cares about the addresses and if there's
|
||
any problem, the process should fail.
|
||
|
||
https://phabricator.freedesktop.org/D1016
|
||
|
||
commit 1fb6401d9d5dbee8ba28a20f3d787a95f13d1883
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Tue Mar 1 15:27:46 2016 -0500
|
||
|
||
candidate: Give lower priority to TCP relayed candidates
|
||
|
||
commit 8ee6d1bbed87fda37ade7b5c5d9483f41037b06a
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Mon Feb 29 16:11:18 2016 -0500
|
||
|
||
udp-turn: Fix binding timeout leak
|
||
|
||
commit 8f1f615e92cd56ad4d8487457c2fde2c4aaa51d9
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Wed Feb 24 22:53:08 2016 -0500
|
||
|
||
conncheck: Update selected pair if necessary
|
||
|
||
commit 65f2eda04c1c73cc7ebc3df2032d528eedc236e1
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Mon Feb 22 19:36:58 2016 -0500
|
||
|
||
conncheck: Don't reset keepalive timer on next keepalive
|
||
|
||
If the keepalive is still being re-send, just let the retries do their
|
||
job. If they don't get a reply, then declare the attempt failed.
|
||
|
||
commit 1ab9d7c104978ea1904aaaad708c1c8c23c77592
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Thu May 26 16:05:36 2016 -0400
|
||
|
||
conncheck: Separate valid and succeded states
|
||
|
||
RFC 5245 specifies that when a mapped-address differs from the address
|
||
from the request was sent, the mapped-address is used to select the
|
||
valid pair, but the source address of the check is used to select the
|
||
pair that succeeded, so they are not the same.
|
||
|
||
commit 0a6c779f1f24099db2c1cd34cd339e240682525d
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Fri Feb 19 20:47:08 2016 -0500
|
||
|
||
udp-turn: Don't expose GSocket
|
||
|
||
UDP turn sockets should never be read frm directly.
|
||
Because they may share the same socket with the non-relay,
|
||
so the incoming data may not be relayed and then the NiceSocket
|
||
API doesn't allow returning the base socket as the source.
|
||
|
||
commit 5b27b028d8ad89214dc7b1ecd018f56aa0333b9c
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Thu Feb 18 14:20:52 2016 -0500
|
||
|
||
conncheck: Make very frequent debug verbose-only
|
||
|
||
commit b7c2eabfd0bd8c1321d9e8450caa8fa6b6ecb5ab
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Mon Feb 15 19:09:58 2016 -0500
|
||
|
||
debug: Enable based on G_MESSAGES_DEBUG
|
||
|
||
commit acfe2b1f366d5f33314db7e9878225f2a70358ef
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Fri Feb 12 01:01:37 2016 -0500
|
||
|
||
agent: Don't emit signal in the middle of recv call
|
||
|
||
commit 716c5805d5b73e94bc6af3637dfd50266150734e
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Wed Feb 10 19:38:52 2016 -0500
|
||
|
||
agent: Update type of peer-reflexive candidate on trickled candidate
|
||
|
||
If a remote candidate matches an already discovered peer-reflexive candidate,
|
||
then the type can be updated to the real type and the foundation
|
||
can be set correctly.
|
||
|
||
commit fc0d3744ebc03f8137866170594968ba61e6be30
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Tue Feb 9 12:52:45 2016 -0500
|
||
|
||
agent: Only try to use the address of the same family to connect to TURN
|
||
|
||
Using a IPv6 local address to connect to a IPv4 relay just creates an
|
||
extra discovery attempt that will not provide something useful.
|
||
|
||
commit c129b05a469b59b576f4700fe9bfe3adca0a48dc
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Sun Feb 7 19:48:07 2016 -0500
|
||
|
||
stun turn usage: Only send the username if short term creds or nonce present
|
||
|
||
This is recommended by the STUN RFC 5389.
|
||
|
||
commit 501f9a82e47076cda0deab8cf54758b608e899aa
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Sun Feb 7 19:41:52 2016 -0500
|
||
|
||
turn: Cache the nonce & realm to remove useless round trips
|
||
|
||
Instead of re-discovering the nonce and realm for every request, cache them
|
||
in th socket.
|
||
|
||
commit 82ea4d71728af95cf0c7bff478f69342a461134b
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Tue Feb 9 11:18:30 2016 -0500
|
||
|
||
conncheck: Stay READY if a new nominated pairs comes in
|
||
|
||
commit 729bd3bb215f0a9a67293dea6df3f8f234eea0ac
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Mon Feb 8 21:04:24 2016 -0500
|
||
|
||
conncheck: Deduplicate conncheck stopping code
|
||
|
||
commit f122e4174d19c60bc434f3986f5c08f8673344bd
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Mon Feb 8 19:41:28 2016 -0500
|
||
|
||
Reset to connecting if reconnected after failed
|
||
|
||
commit 9c1a41b06ab459ce33f32d25ce258fb21ba49047
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Thu Jan 14 17:59:16 2016 -0500
|
||
|
||
agent: Add warning on ignored result
|
||
|
||
commit a357b17f5f3415320b9ec7122738396ccd998521
|
||
Author: Fabrice Bellet <fabrice@bellet.info>
|
||
Date: Mon Apr 4 23:02:52 2016 +0100
|
||
|
||
conncheck: display controlling mode of stun requests
|
||
|
||
This patch makes the debug log more explicit about the agent
|
||
controlling role for each stun request sent. It helps to debug
|
||
role conflict resolution.
|
||
|
||
Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Differential Revision: https://phabricator.freedesktop.org/D877
|
||
|
||
commit b986d6e5f2ee0b7b0e09031c1a369bf89153e4c5
|
||
Author: Fabrice Bellet <fabrice@bellet.info>
|
||
Date: Mon Apr 4 22:38:07 2016 +0100
|
||
|
||
agent: remove newline from debug output
|
||
|
||
Just a cosmetic fix.
|
||
|
||
Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Differential Revision: https://phabricator.freedesktop.org/D872
|
||
|
||
commit e0ed4fb3a236710846d9129438e0077782569633
|
||
Author: Jakub Adam <jakub.adam@ktknet.cz>
|
||
Date: Mon Apr 4 21:52:29 2016 +0100
|
||
|
||
socket: refactor nice_socket_is_base_of()
|
||
|
||
• rename to nice_socket_is_based_on() and swap the order of arguments
|
||
accordingly; the implementation doesn't have to use the confusing
|
||
'return other->is_base_of()' pattern anymore
|
||
• fix potential NULL dereferences
|
||
|
||
The argument order in agent_recv_message_unlocked() was already wrongly
|
||
swapped in 1732c7d6 and thus this commit isn't changing it back because
|
||
that order has become the correct one.
|
||
|
||
Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Differential Revision: https://phabricator.freedesktop.org/D866
|
||
|
||
commit 38268e53fde8cd97055d88d2066c0016fe04b31b
|
||
Author: Jakub Adam <jakub.adam@ktknet.cz>
|
||
Date: Mon Apr 4 21:46:05 2016 +0100
|
||
|
||
socket: fix wrong function called in nice_socket_is_base_of()
|
||
|
||
We have to call is_base_of "virtual function pointer" of 'other'
|
||
object, not 'sock', since 'other' is the structure whose base
|
||
NiceSocket we need to get from its private data.
|
||
|
||
For instance calling nice_socket_is_base_of() with 'sock' and 'other'
|
||
being respectively pseudo-SSL and UDP-TURN-over-TCP invoked is_base_of
|
||
variant for pseudo-SSL, casting other->priv into PseudoSSLPriv *, but
|
||
other->priv is actually TurnTcpPriv *. It must be called the other way
|
||
around.
|
||
|
||
https://phabricator.freedesktop.org/T7335
|
||
https://phabricator.freedesktop.org/T7336
|
||
|
||
Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Reviewed-by: José Antonio Santos Cadenas <santoscadenas@gmail.com>
|
||
Reviewed-by: Philip Withnall <philip@tecnocode.co.uk>
|
||
Reviewed-by: José Antonio Santos Cadenas <santoscadenas@gmail.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D785
|
||
|
||
commit 7037ab4cf384edd9f700bc221a9d980b30d9c64f
|
||
Author: Fabrice Bellet <fabrice@bellet.info>
|
||
Date: Mon Apr 4 21:38:59 2016 +0100
|
||
|
||
conncheck: implement a "triggered queue" list
|
||
|
||
The checks should not be sent immediately in priv_conn_check_initiate(),
|
||
but be put into the "triggered queue", see "7.2.1.4 Triggered Checks".
|
||
This patch implements this triggered checks list, and uses it to enforce a
|
||
pacing of STUN transactions, no more than one per Ta ms, according to
|
||
"B.1. Pacing of STUN Transactions".
|
||
|
||
Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Reviewed-by: Philip Withnall <philip@tecnocode.co.uk>
|
||
Differential Revision: https://phabricator.freedesktop.org/D802
|
||
|
||
commit 1732c7d6a7a104438412309373818e493a2504c9
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Sun Mar 6 15:16:18 2016 -0500
|
||
|
||
agent: Fix argument order
|
||
|
||
Fixes crash reported on https://phabricator.freedesktop.org/D786
|
||
|
||
commit aac283e0fa75b226fe2431403761ebd45e4f5614
|
||
Author: Fabrice Bellet <fabrice@bellet.info>
|
||
Date: Sat Mar 5 18:46:48 2016 +0000
|
||
|
||
ice: fix the debug of the presence of the controlling/controlled attrib
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D807
|
||
|
||
commit ed75d55cf279613bb736f7646d3010d816797ddf
|
||
Author: Jakub Adam <jakub.adam@ktknet.cz>
|
||
Date: Wed Mar 2 00:01:19 2016 +0000
|
||
|
||
agent: fix relay candidate discovery on hosts having several IPs
|
||
|
||
When a message is received from a TURN server and we manage to find a
|
||
local relay candidate with matching stream and component IDs, we should
|
||
also check whether the message came from the candidate's respective
|
||
socket.
|
||
|
||
We should do this because there might still be some pending TURN
|
||
candidate discovery with the same server from a different local host IP
|
||
and the message may be a response to our allocate request. If
|
||
nice_udp_turn_socket_parse_recv_message() is passed such request, it can
|
||
make some wrong assumptions and modify it like in the case of reliable
|
||
UDP-TURN-OVER-TCP by removing (supposed) RFC4571 framing, which in turn
|
||
causes the reply to be unrecognized and discarded.
|
||
|
||
Because of this, any subsequent replies following the first successful
|
||
allocate response from that server couldn't create any additional relay
|
||
candidates.
|
||
|
||
Maniphest Tasks: https://phabricator.freedesktop.org/T7336
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D786
|
||
|
||
commit 1493a381d5bf6e15348c2bc17270f45b69cb70d2
|
||
Author: Philip Withnall <philip@tecnocode.co.uk>
|
||
Date: Tue Mar 1 23:50:11 2016 +0000
|
||
|
||
build: Update autogen.sh from GNOME template
|
||
|
||
https://wiki.gnome.org/Projects/GnomeCommon/Migration#autogen.sh
|
||
|
||
commit bc620c0de966b47d761bbcb1279dac6221a5a30e
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Tue Mar 1 23:29:10 2016 +0000
|
||
|
||
component.c: Fix memory leak
|
||
|
||
If nicesocket is not added to a component it will be leaked.
|
||
|
||
This is the case of active tcp sockets
|
||
|
||
Change-Id: I57fefffef71d35ce9871139ee1064181f6fe125b
|
||
Reviewed-by: José Antonio Santos Cadenas <santoscadenas@gmail.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D822
|
||
|
||
commit 38c5e66886cb8138d6be57b8a4721d9b42a358b7
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Tue Mar 1 23:23:14 2016 +0000
|
||
|
||
agent: Use provided CandidatePair rather than re-finding a pair
|
||
|
||
In priv_update_selected_pair(), commit 57393333 changed the code to
|
||
re-find a CandidatePair matching the given lfoundation and rfoundation.
|
||
However, the foundation does not uniquely identify candidate pairs,
|
||
and if we’re aiming to set a specific candidate pair as the selected
|
||
pair, this could result in the wrong pair being selected.
|
||
|
||
This can happen when handling multiple similar candidate pairs, such as
|
||
when generating peer reflexive candidates from multiple sources.
|
||
|
||
See https://tools.ietf.org/html/rfc5245#section-2.4.
|
||
|
||
Originally spotted by Fabrice Bellet in
|
||
https://phabricator.freedesktop.org/T3557.
|
||
|
||
Reviewed-by: José Antonio Santos Cadenas <santoscadenas@gmail.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D742
|
||
|
||
commit 70981d41edf46a09393017f3de34748fcecea046
|
||
Author: Philip Withnall <philip@tecnocode.co.uk>
|
||
Date: Tue Mar 1 23:05:20 2016 +0000
|
||
|
||
simple-example: transmission can begin earlier than in ready state
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D819
|
||
|
||
commit 47eaf50a99d91c4a666f05c4de24613706847c88
|
||
Author: Philip Withnall <philip@tecnocode.co.uk>
|
||
Date: Tue Mar 1 23:04:14 2016 +0000
|
||
|
||
test-new-dribble: wait until ragent reaches state completed
|
||
|
||
The test didn't let enough time for ragent to reach the completed state
|
||
after obtaining its remote candidates and switching to connecting state.
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D817
|
||
|
||
commit 4e68244a51698aefdf44dd1ceb17b95275e655bf
|
||
Author: Philip Withnall <philip@tecnocode.co.uk>
|
||
Date: Tue Mar 1 23:02:52 2016 +0000
|
||
|
||
conncheck: reorder the connection list when priorities are updated
|
||
|
||
The update of pairs priorities due to agent role change requires the
|
||
conncheck list to be reordered to reflect this modification.
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D806
|
||
|
||
commit 0f1e6c64515871298b115b497b019506b8065235
|
||
Author: Philip Withnall <philip@tecnocode.co.uk>
|
||
Date: Tue Mar 1 23:01:14 2016 +0000
|
||
|
||
conncheck: fix keepalive stun agent initialisation
|
||
|
||
With this patch, we send keepalive binding requests using agent
|
||
compatibility flags, instead of RFC 3489 classic stun. The peer stun
|
||
agent will known how to handle it, and won't be confused by the
|
||
uncompatible RFC 3489 message, causing "no cookie" errors in the debug
|
||
log.
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D804
|
||
|
||
commit 17488a20d8db8ea1f8fa2d7a44090070407d6db8
|
||
Author: Philip Withnall <philip@tecnocode.co.uk>
|
||
Date: Tue Mar 1 22:58:15 2016 +0000
|
||
|
||
conncheck: foundations are shared across streams
|
||
|
||
This patch fixes a bug where the foundation definition shouldn't take
|
||
into account the stream the pair belongs to. This is important, because
|
||
the ordinary checks algorithm will change pair state from Frozen to
|
||
Waiting, by selecting pairs from other streams sharing the same
|
||
foundation than already succeeded pairs.
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D815
|
||
|
||
commit 3ce45c25af238fb4d9a040abb44597531140db2d
|
||
Author: Philip Withnall <philip@tecnocode.co.uk>
|
||
Date: Tue Mar 1 22:37:33 2016 +0000
|
||
|
||
test-priority: ignore the local preference
|
||
|
||
The local preference depends on the rank of the IP address in the list
|
||
of all IP addresses available of the box running the test. As this value
|
||
is not fixed we ignore it in the test.
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D818
|
||
|
||
commit c309905ff446bed2dc47811023b98bc586a02d63
|
||
Author: Philip Withnall <philip@tecnocode.co.uk>
|
||
Date: Tue Mar 1 22:33:51 2016 +0000
|
||
|
||
conncheck: nominate only one matching pair
|
||
|
||
This patch fixes a bug in priv_mark_pair_nominated(), where the local
|
||
candidate was not passed to the function, so removing the possibility to
|
||
find which local candidate the check was sent to.
|
||
|
||
Reviewed-by: Philip Withnall <philip@tecnocode.co.uk>
|
||
Differential Revision: https://phabricator.freedesktop.org/D808
|
||
|
||
commit 80973c096de872983bc60cd28a84653931f8d601
|
||
Author: Philip Withnall <philip@tecnocode.co.uk>
|
||
Date: Tue Mar 1 22:28:35 2016 +0000
|
||
|
||
conncheck: add more debug information
|
||
|
||
Add a more debug details, specifically in some places, it is interesting
|
||
to have the src and dst IP addresses of the pairs being checked, and
|
||
also to make the difference between log related to different stream ids.
|
||
|
||
Reviewed-by: Philip Withnall <philip@tecnocode.co.uk>
|
||
Differential Revision: https://phabricator.freedesktop.org/D803
|
||
|
||
commit 41ab61def82aa275649afd5f4a3fcb43e75fb360
|
||
Author: Mike Ruprecht <cmaiku@gmail.com>
|
||
Date: Mon Jan 18 12:42:46 2016 +0000
|
||
|
||
agent: Fix not setting UPnP timeout on second gather_candidates()
|
||
|
||
If the first call to nice_agent_gather_candidates() partially succeeds
|
||
(setting a UPnP agent and timeout), then fails before starting
|
||
gathering, a second call to nice_agent_gather_candidates() would fail to
|
||
set a new UPnP timeout because the UPnP initialisation block would be
|
||
skipped. That means gathering would never succeed due to timing out on
|
||
UPnP.
|
||
|
||
Fix that by setting the UPnP timeout whenever a new pending UPnP mapping
|
||
is added.
|
||
|
||
https://phabricator.freedesktop.org/T3534
|
||
|
||
Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
|
||
commit 9638bc132f909177f6ecfb86cdd17af557a35c56
|
||
Author: Jose Antonio Santos Cadenas <santoscadenas@gmail.com>
|
||
Date: Thu Dec 3 15:01:35 2015 +0100
|
||
|
||
configure.ac: Update glib version
|
||
|
||
As udp-bsd.ccode is using G_IO_ERROR_CONNECTION_CLOSED glib 2.44
|
||
is required.
|
||
|
||
Change-Id: I1bb63f2484c513c58eeec312ba0835164604c40c
|
||
Reviewed-by: Philip Withnall <philip@tecnocode.co.uk>
|
||
https://phabricator.freedesktop.org/T3492
|
||
|
||
commit 3e71f42c8b15790e252d850ba42a7ae7e7cc69a9
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Oct 7 19:03:58 2015 +0100
|
||
|
||
pseudotcp: Use labs() rather than abs() for handling long integers
|
||
|
||
This fixes a compiler warning and prevents a possible truncation.
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D345
|
||
|
||
commit 53283c218a5eb7a29e7019ac320e74f9dbe4b3fc
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Mon Jun 22 11:30:31 2015 +0100
|
||
|
||
tests: Enable G_MESSAGES_DEBUG for all unit tests
|
||
|
||
Now that we’re using automake’s parallel test harness, it automatically
|
||
redirects all the debug log spew away from the console, so we should
|
||
always have it enabled.
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D292
|
||
|
||
commit aef748ec7d0b06067312e5cc761a6375cd0f699c
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Thu Oct 1 17:52:08 2015 +0100
|
||
|
||
build: Set repository callsign in .arcconfig
|
||
|
||
This fixes `arc diff` to select the right repository when submitting
|
||
patches.
|
||
|
||
commit 008739a5a60e591629e38da9b8b7065dbc2c746f
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Sep 30 14:57:10 2015 +0100
|
||
|
||
agent: Correctly namespace Component and its methods
|
||
|
||
Remove all references to the old, unnamespaced versions. This should
|
||
cause no functional changes.
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D309
|
||
|
||
commit 529bc193d56522b10a4de83409396b3316863934
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Sep 30 14:34:34 2015 +0100
|
||
|
||
agent: Correctly namespace Stream and its methods
|
||
|
||
Remove all references to the old, unnamespaced versions. This should
|
||
cause no functional changes.
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D308
|
||
|
||
commit ef2b58f64887546e426dd8cda382f2908f84caca
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Sep 30 14:11:14 2015 +0100
|
||
|
||
agent: Turn Component into a GObject
|
||
|
||
This makes it reference-counted. This will be useful for allowing
|
||
GDatagramBased and GIOStream objects to hold references to the stream
|
||
and component they are interested in, allowing removal of the global
|
||
NiceAgent lock previously needed to look up the component for every I/O
|
||
operation.
|
||
|
||
Deprecate all the old methods until it’s properly namespaced.
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D307
|
||
|
||
commit 1f08419382c52c7e796da06c9271a362aa60333d
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Sep 30 14:10:32 2015 +0100
|
||
|
||
agent: Turn Stream into a GObject
|
||
|
||
This makes it reference-counted. This will be useful for allowing
|
||
GDatagramBased and GIOStream objects to hold references to the stream
|
||
and component they are interested in, allowing removal of the global
|
||
NiceAgent lock previously needed to look up the component for every I/O
|
||
operation.
|
||
|
||
It also means that nice_stream_close() could eventually become
|
||
asynchronous, which would fix a few race conditions.
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D306
|
||
|
||
commit da70716162b2085ca4db6e7efd446fcda7bd488d
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Sep 30 17:59:04 2015 +0100
|
||
|
||
tests: Update expected priority values in test-priority
|
||
|
||
This is a follow up to T3324, to update the test case to match the new
|
||
values generated.
|
||
|
||
Bug: https://phabricator.freedesktop.org/T3324
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D301
|
||
|
||
commit 66e47aa39f9cd3666e610fab78caa0c7d8f9c410
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Sep 30 17:54:21 2015 +0100
|
||
|
||
tests: Use g_assert_cmpuint() to make test failures easier to diagnose
|
||
|
||
Now we can actually see the priority numbers which are unequal.
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D300
|
||
|
||
commit 1ae15f66af2af17e991ab028ca16a1200fd5f4e5
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Sep 30 17:53:14 2015 +0100
|
||
|
||
tests: Set candidate addresses in test-priority
|
||
|
||
This avoids an assertion failure in nice_address_to_string() when the
|
||
addresses are compared for priority.
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D299
|
||
|
||
commit ea3348020da586f20e1a64c9732405e730563616
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Sep 30 17:46:47 2015 +0100
|
||
|
||
agent: Remove redundant GLIB_CHECK_VERSION macros
|
||
|
||
We depend on GLib 2.36.0, which is a higher version than any of these
|
||
version checks cared about, so they were all trivially true or false.
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D298
|
||
|
||
commit 9f10231fc787e4683e896bf35f086906a5b16c03
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Sep 30 17:44:44 2015 +0100
|
||
|
||
tests: Remove g_thread_init() calls
|
||
|
||
We depend on GLib 2.36.0; g_thread_init() has been deprecated since
|
||
2.32.0, when thread initialisation was changed to happen automatically.
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D297
|
||
|
||
commit dac3e280d6f3fd792f1d79313debd03c0df282c4
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Sep 30 17:41:36 2015 +0100
|
||
|
||
tests: Remove g_type_init() calls
|
||
|
||
We depend on GLib 2.36.0, which deprecated g_type_init() since GType
|
||
initialisation is now done automatically.
|
||
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
Differential Revision: https://phabricator.freedesktop.org/D296
|
||
|
||
commit fae0f9d37c6e34f34c92dee85384c29e565bdbce
|
||
Author: Jakub Adam <jakub.adam@ktknet.cz>
|
||
Date: Fri Sep 11 11:57:54 2015 +0100
|
||
|
||
conncheck: rename priv_process_response_check_for_peer_reflexive()
|
||
|
||
Renamed the function to priv_process_response_check_for_reflexive()
|
||
because it now checks also for server reflexive candidates.
|
||
|
||
Updated the documentation to indicate that the function never returns
|
||
NULL.
|
||
|
||
Maniphest Tasks: https://phabricator.freedesktop.org/T115
|
||
Differential Revision: https://phabricator.freedesktop.org/D243
|
||
Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
|
||
commit 02852728ef347f5cb4c9227848b266c72b5fe38b
|
||
Author: Jakub Adam <jakub.adam@ktknet.cz>
|
||
Date: Fri Sep 11 11:56:02 2015 +0100
|
||
|
||
conncheck: generate candidate pair for valid srflx candidate
|
||
|
||
In priv_process_response_check_for_peer_reflexive(), mere presence of a candidate in local_candidates doesn't mean there's also some candidate
|
||
pair in conncheck_list using it - for instance that candidate may be server reflexive, for which no check pairs are initially created (see
|
||
conn_check_add_for_candidate_pair()).
|
||
|
||
If we fail to find corresponding pair upon receiving such candidate's IP in a conncheck response's XOR-MAPPED-ADDRESS attribute, we shall add a
|
||
new one in a similar way we would add a new pair for a just discovered peer reflexive candidate.
|
||
|
||
Previous priv_process_response_check_for_peer_reflexive() implementation would return NULL, causing a CandidateCheckPair with local candidate of
|
||
type HOST to be wrongly selected even though the local host IP might not be directly accessible by the remote counterpart (e.g. it's an address
|
||
on a private network segment). In practice this was coming through as a duplex connection that libnice was reporting as properly established,
|
||
but only one direction of the communication was actually working.
|
||
|
||
Maniphest Tasks: https://phabricator.freedesktop.org/T115
|
||
Differential Revision: https://phabricator.freedesktop.org/D242
|
||
Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
|
||
commit 84eaa12b0b1a76c45ce2d77294e0477c10552cd4
|
||
Author: Jakub Adam <jakub.adam@ktknet.cz>
|
||
Date: Fri Sep 11 11:33:51 2015 +0100
|
||
|
||
agent: check for base socket in _tcp_sock_is_writable()
|
||
|
||
The argument passed into the callback is always a base (TCP/UDP) socket,
|
||
which can't be directly compared with local candidate's sockptr (may be
|
||
TURN, http, or other socket wrapping another one). We're in fact
|
||
interested whether sock is a base socket of sockptr.
|
||
|
||
Maniphest Tasks: T114
|
||
Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Differential Revision: https://phabricator.freedesktop.org/D241
|
||
|
||
commit 837c8953fe87bdd5d5bccc444e72739100578ef8
|
||
Author: Jakub Adam <jakub.adam@ktknet.cz>
|
||
Date: Fri Sep 11 11:29:39 2015 +0100
|
||
|
||
socket: add nice_socket_is_base_of()
|
||
|
||
This will be used in the next commit.
|
||
|
||
Maniphest Tasks: T114
|
||
Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Differential Revision: https://phabricator.freedesktop.org/D240
|
||
|
||
commit c6bc33c031493e0db11a1f57055a656f6428c60a
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Thu Jul 10 08:32:04 2014 +0100
|
||
|
||
build: Bump GLib dependency to 2.36
|
||
|
||
This is needed for G_IO_ERROR_BROKEN_PIPE, which is used in the I/O
|
||
stream code.
|
||
|
||
Reported by Emanuele Bizzarri <emabiz76@gmail.com> on the mailing list.
|
||
|
||
commit 757f8aecdb4fda86b2bbac828a3acc528d8eb8bc
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Fri Sep 4 08:14:08 2015 +0100
|
||
|
||
stun: Disable debug by default
|
||
|
||
To match debug_enable in agent/debug.c. Debug can still be enabled by
|
||
calling stun_debug_enable() or nice_debug_enable().
|
||
|
||
Spotted on the mailing list by Tom Chen.
|
||
|
||
commit 2eaa8b3277f4f39515ff5dc7b512a44fd79e7275
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Mon Jun 29 16:30:12 2015 +0100
|
||
|
||
agent: Add assertions to check component state transitions are valid
|
||
|
||
There is no point in the NiceComponents having a state machine if the
|
||
state transition graph is not documented or enforced. Document and
|
||
enforce it.
|
||
|
||
http://phabricator.freedesktop.org/T120
|
||
|
||
commit 3f54b333525e2a4ae35e0be439062900fb8ab7c3
|
||
Merge: 1034832 181ad3a
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Sep 2 16:44:45 2015 +0100
|
||
|
||
ms-ice: ensure distinct candidate priority for multihomed hosts
|
||
|
||
Summary:
|
||
Offering multiple host candidates with equal priorities could lead to unpredictable candidate pair selection by our counterparty.
|
||
|
||
Fixes call disconnection by MS Lync client after 30 seconds while VPN (2nd IP) was active on libnice host.
|
||
|
||
Maniphest Tasks: T3324
|
||
|
||
Reviewers: pwithnall
|
||
|
||
Projects: #libnice
|
||
|
||
Reviewed By: pwithnall
|
||
|
||
Subscribers: pwithnall
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D234
|
||
|
||
commit 181ad3a9bf54b9d6c4e0921ae148bab6d9fd0b3a
|
||
Author: Jakub Adam <jakub.adam@ktknet.cz>
|
||
Date: Wed Sep 2 16:43:02 2015 +0100
|
||
|
||
candidate: use distinct priority also for non-MS compatibilities
|
||
|
||
Maniphest Tasks: T3324
|
||
|
||
Reviewers: pwithnall
|
||
|
||
Projects: #libnice
|
||
|
||
Reviewed By: pwithnall
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D239
|
||
|
||
commit 799b322d6c654b864b5442cdaaa62aaee81d4901
|
||
Author: Jakub Adam <jakub.adam@ktknet.cz>
|
||
Date: Wed Sep 2 16:41:49 2015 +0100
|
||
|
||
conncheck: give temporary candidate_priority a base_addr
|
||
|
||
Summary:
|
||
Fixes "(nice_address_to_string): should not be reached" errors when calling nice_candidate_ms_ice_priority() because of invalid NiceAddress.
|
||
|
||
Maniphest Tasks: T3324
|
||
|
||
Reviewers: pwithnall
|
||
|
||
Projects: #libnice
|
||
|
||
Reviewed By: pwithnall
|
||
|
||
Subscribers: pwithnall
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D238
|
||
|
||
commit 85cd01c1396ef244f90e0d9c995fab29ed121f23
|
||
Author: Jakub Adam <jakub.adam@ktknet.cz>
|
||
Date: Wed Sep 2 16:41:49 2015 +0100
|
||
|
||
ms-ice: ensure distinct candidate priority for multihomed hosts
|
||
|
||
Summary:
|
||
Offering multiple host candidates with equal priorities could lead to unpredictable candidate pair selection by our counterparty.
|
||
|
||
Fixes call disconnection by MS Lync client after 30 seconds while VPN (2nd IP) was active on libnice host.
|
||
|
||
Maniphest Tasks: T3324
|
||
|
||
Reviewers: pwithnall
|
||
|
||
Projects: #libnice
|
||
|
||
Reviewed By: pwithnall
|
||
|
||
Subscribers: pwithnall
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D234
|
||
|
||
commit 88ed42619049ac1e3fe3a6e481df8aeb95033ac0
|
||
Author: Jakub Adam <jakub.adam@ktknet.cz>
|
||
Date: Wed Sep 2 16:41:48 2015 +0100
|
||
|
||
discovery: assign candidate priority after base_addr is set
|
||
|
||
Summary: So that we can take the base address into account in the calculation.
|
||
|
||
Maniphest Tasks: T3324
|
||
|
||
Reviewers: pwithnall
|
||
|
||
Projects: #libnice
|
||
|
||
Reviewed By: pwithnall
|
||
|
||
Subscribers: pwithnall
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D235
|
||
|
||
commit 10348322a960258043363e7c84e78c4821c90412
|
||
Merge: abdab05 ab4ced5
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Sep 2 16:34:01 2015 +0100
|
||
|
||
ms-turn: don't wait for a reply to STUN_SEND request
|
||
|
||
Maniphest Tasks: T126
|
||
|
||
Reviewers: pwithnall
|
||
|
||
Projects: #libnice
|
||
|
||
Reviewed By: pwithnall
|
||
|
||
Subscribers: pwithnall
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D223
|
||
|
||
commit ab4ced5a46a7edba7cd49c0495bc41cd8fff7cc2
|
||
Author: Jakub Adam <jakub.adam@ktknet.cz>
|
||
Date: Wed Sep 2 16:32:05 2015 +0100
|
||
|
||
ms-turn: don't wait for a reply to STUN_SEND request
|
||
|
||
As per [MS-TURN] Section 2.2.1, TURN message type 0x0104 "Send request
|
||
response" isn't supported and the TURN server MUST NOT send them. Thus,
|
||
libnice should not remember Send requests in agent->sent_ids because
|
||
without replies coming, the number of allowed pending transaction gets
|
||
quickly exhausted, causing our data packets to be dropped until a
|
||
request timeout frees some space in the queue.
|
||
|
||
This behavior resulted in choppy reception of our audio on a Lync client
|
||
when connected via Lync Edge (TURN) Server.
|
||
|
||
Maniphest Tasks: T126
|
||
|
||
Reviewers: pwithnall
|
||
|
||
Projects: #libnice
|
||
|
||
Reviewed By: pwithnall
|
||
|
||
Subscribers: pwithnall
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D223
|
||
|
||
commit abdab053af41068406caf95e80a64c512fd3db90
|
||
Merge: 03d11b4 490b16f
|
||
Author: Philip Withnall <philip@tecnocode.co.uk>
|
||
Date: Sat Aug 29 23:26:00 2015 +0100
|
||
|
||
Creating TCP sockets with TCP_NODELAY option set to TRUE
|
||
|
||
Summary:
|
||
Disable Nagling for underlying TCP sockets used by libnice, because they
|
||
are typically used for streaming applications, or for pseudo-TCP; the
|
||
bandwidth in both cases is harmed by Nagling.
|
||
|
||
Based on a patch by Vadim Genkin.
|
||
|
||
Maniphest Tasks: T3317
|
||
|
||
Reviewers: vadimgenkin, pwithnall
|
||
|
||
Projects: #libnice
|
||
|
||
Reviewed By: pwithnall
|
||
|
||
Subscribers: pwithnall, vadimgenkin
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D230
|
||
|
||
commit 490b16f400284c5df6508fd095d592efdfbc62ae
|
||
Author: Philip Withnall <philip@tecnocode.co.uk>
|
||
Date: Sat Aug 29 22:39:56 2015 +0100
|
||
|
||
Creating TCP sockets with TCP_NODELAY option set to TRUE
|
||
|
||
Disable Nagling for underlying TCP sockets used by libnice, because they
|
||
are typically used for streaming applications, or for pseudo-TCP; the
|
||
bandwidth in both cases is harmed by Nagling.
|
||
|
||
Based on a patch by Vadim Genkin.
|
||
|
||
Maniphest Tasks: T3317
|
||
|
||
Reviewers: pwithnall
|
||
|
||
Projects: #libnice
|
||
|
||
Subscribers: pwithnall, vadimgenkin
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D230
|
||
|
||
commit 03d11b49b0ac14ff320192562df57898ea9f94b4
|
||
Merge: dddca10 1c34734
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Sat Aug 29 20:05:00 2015 +0100
|
||
|
||
Fix agent leak in case component socket is reset remotely
|
||
|
||
Summary: The patch fixes the issue where agent reference count is not properly decremented causing instance leak in cases where component's socket is reset remotely.
|
||
|
||
Reviewers: #libnice, pwithnall
|
||
|
||
Projects: #libnice
|
||
|
||
Reviewed By: #libnice, pwithnall
|
||
|
||
Subscribers: pwithnall, maximgolunov
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D236
|
||
|
||
commit 1c34734cd105c6cca0ec8bbb908002c4bfb007b3
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Sat Aug 29 20:04:03 2015 +0100
|
||
|
||
Fix agent leak in case component socket is reset remotely
|
||
|
||
Summary: The patch fixes the issue where agent reference count is not properly decremented causing instance leak in cases where component's socket is reset remotely.
|
||
|
||
Reviewers: #libnice, pwithnall
|
||
|
||
Projects: #libnice
|
||
|
||
Reviewed By: #libnice, pwithnall
|
||
|
||
Subscribers: pwithnall, maximgolunov
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D236
|
||
|
||
commit dddca10ceff20e3578fc901b9919c3d20f87b7b6
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Aug 19 09:24:27 2015 +0100
|
||
|
||
build: Update .gitignore
|
||
|
||
Add stun/usages/.dirstamp.
|
||
|
||
commit 6c9afb4db35168cc699ff0aa2e56b127f3706083
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Aug 19 09:22:49 2015 +0100
|
||
|
||
build: Fix multiple definition of CLEANFILES
|
||
|
||
It’s already defined in common.mk.
|
||
|
||
commit 041158c4fe36c4af6d56cd4445946d7f5e5be57d
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Aug 19 09:20:01 2015 +0100
|
||
|
||
build: Add .arcconfig file
|
||
|
||
This completes the transition to Phabricator; everyone should be using
|
||
the same project settings now.
|
||
|
||
https://phabricator.freedesktop.org/tag/libnice/
|
||
|
||
commit 8f2a14b1d6af73e91c5712898e8a3e97308920a6
|
||
Merge: e5e77b6 ad0003b
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Aug 19 09:19:18 2015 +0100
|
||
|
||
socket: Handle ECONNRESET as EWOULDBLOCK on Windows
|
||
|
||
Summary:
|
||
Some versions of Windows can return ECONNRESET for UDP recvmsg() calls
|
||
if they would otherwise block. Hence, handle the two equivalently; this
|
||
should not affect behaviour on Linux, which apparently does not return
|
||
ECONNRESET for UDP recvmsg() calls at all.
|
||
|
||
https://phabricator.freedesktop.org/T121
|
||
|
||
Maniphest Tasks: T121
|
||
|
||
Reviewers: ocrete
|
||
|
||
Projects: #libnice
|
||
|
||
Reviewed By: ocrete
|
||
|
||
Subscribers: stwiname, felixSchl
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D227
|
||
|
||
commit e5e77b67fb6152dd9fb0af3d7410a428299504d3
|
||
Merge: 6835e7b a2e25cf
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Wed Aug 19 09:16:53 2015 +0100
|
||
|
||
socket: Close base socket for a TCP passive socket when closing parent
|
||
|
||
Summary:
|
||
Otherwise the base socket will leak. Spotted by Vadim Genkin.
|
||
|
||
https://phabricator.freedesktop.org/T125
|
||
|
||
Maniphest Tasks: T125
|
||
|
||
Reviewers: ocrete
|
||
|
||
Projects: #libnice
|
||
|
||
Reviewed By: ocrete
|
||
|
||
Subscribers: vadimgenkin
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D228
|
||
|
||
commit a2e25cf49b24c2012e8e9058ecc7e62f1e027cb3
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Tue Aug 18 14:58:23 2015 +0100
|
||
|
||
socket: Close base socket for a TCP passive socket when closing parent
|
||
|
||
Otherwise the base socket will leak. Spotted by Vadim Genkin.
|
||
|
||
https://phabricator.freedesktop.org/T125
|
||
|
||
commit 6835e7b7f4a20078d508444659c636fc98e680fc
|
||
Merge: e1f748c 6b3e59c
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Tue Aug 18 14:03:41 2015 +0100
|
||
|
||
agent: Remove unused inet_pton() function
|
||
|
||
Summary:
|
||
As spotted by Felix <felixschlitter@gmail.com>. This is a static
|
||
function which is totally unused in this compilation unit and is causing
|
||
build failures with `-Werror=unused-function`.
|
||
|
||
Maniphest Tasks: T123
|
||
|
||
Reviewers: felixSchl, ocrete
|
||
|
||
Projects: #libnice
|
||
|
||
Differential Revision: https://phabricator.freedesktop.org/D221
|
||
|
||
commit 6b3e59c5a670d5117ed293ae612082dcd047ba8a
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Tue Jun 30 14:39:51 2015 +0100
|
||
|
||
agent: Remove unused inet_pton() function
|
||
|
||
As spotted by Felix <felixschlitter@gmail.com>. This is a static
|
||
function which is totally unused in this compilation unit and is causing
|
||
build failures with -Werror=unused-function.
|
||
|
||
http://phabricator.freedesktop.org/T123
|
||
|
||
commit ad0003b48414c789a1191fd5f44fec41e694dfa0
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Tue Aug 18 13:33:23 2015 +0100
|
||
|
||
socket: Handle ECONNRESET as EWOULDBLOCK on Windows
|
||
|
||
Some versions of Windows can return ECONNRESET for UDP recvmsg() calls
|
||
if they would otherwise block. Hence, handle the two equivalently; this
|
||
should not affect behaviour on Linux, which apparently does not return
|
||
ECONNRESET for UDP recvmsg() calls at all.
|
||
|
||
https://phabricator.freedesktop.org/T121
|
||
|
||
commit e1f748cccacd81cce4db338d0203dc49bc915a30
|
||
Author: Jakub Adam <jakub.adam@ktknet.cz>
|
||
Date: Thu Jun 18 09:05:21 2015 +0200
|
||
|
||
conncheck: set writable callback to socket from TCP active connect
|
||
|
||
A new socket created in nice_tcp_active_socket_connect() should have its
|
||
writable callback set, because it's possible for it to become a base
|
||
socket of a peer reflexive candidate, if some is discovered by
|
||
connection checks on that TCP active candidate.
|
||
|
||
Previously, when such prflx candidate became selected, without write_cb
|
||
on the socket the agent was never notified about it becoming writable
|
||
again after the socket's buffer got filled up. This caused the data flow
|
||
to hang permanently.
|
||
|
||
Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Reviewed-by: Olivier Crête <olivier.crete@collabora.com>
|
||
|
||
http://phabricator.freedesktop.org/T117
|
||
|
||
commit cd61af3114a51df53619fb0460ace2b3660fc5da
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Tue Jun 30 14:29:43 2015 +0100
|
||
|
||
pseudotcp: Only define errnos on Windows if not already defined
|
||
|
||
Recent versions of MinGW define at least ECONNABORTED and EAFNOSUPPORT,
|
||
so only define the various socket errnos if they are not defined
|
||
already.
|
||
|
||
Based on a patch by Alexey Pawlow <alexey.pawlow@gmail.com> and Felix
|
||
<felixschlitter@gmail.com>.
|
||
|
||
Reviewed-by: Olivier Crete <olivier.crete@collabora.com>
|
||
Reviewed-by: Felix Schlitter <felixschlitter@gmail.com>
|
||
|
||
http://phabricator.freedesktop.org/T122
|
||
|
||
commit 3cccc311b1becf4307f5a4004734d8f7b2cf84f6
|
||
Author: Felix Schlitter <felixschlitter@gmail.com>
|
||
Date: Tue Jun 30 07:37:31 2015 +1200
|
||
|
||
Use G_GSIZE_FORMAT instead of %zu
|
||
|
||
The C runtime on windows does not implement a printf that understands
|
||
%zu and other C99 format specifiers. Use G_GSIZE_FORMAT instead. This
|
||
is further consistent with the rest of the code base that makes use of
|
||
G_GSIZE_FORMAT throughout.
|
||
|
||
https://github.com/libnice/libnice/pull/3
|
||
|
||
commit c4d5ec572ae0ede14d13d9ce5b193cdcb36b07a1
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Thu Sep 18 19:33:10 2014 -0400
|
||
|
||
Split "verbose" on-every-packet messages to a verbose log
|
||
|
||
This way, the regular log will only contain connection-time information.
|
||
|
||
commit 2d24ef532d1b6ec684f28d52aa0592dfdfb7e067
|
||
Author: Olivier Crête <olivier.crete@collabora.com>
|
||
Date: Thu Sep 18 19:33:06 2014 -0400
|
||
|
||
stun: Remove annoying non-error on non-STUN packet
|
||
|
||
commit 81a929ac141aae66b6450e8ce93cb357ed404cda
|
||
Author: Timo Gurr <timo.gurr@gmail.com>
|
||
Date: Mon Jun 1 16:10:16 2015 +0200
|
||
|
||
configure: Fix configure failure when building without gstreamer support
|
||
|
||
Error introduced in 20ea22e0a11a9bdfe4d8125b68083249b694338a, resulting in a
|
||
configure/build error when building without gstreamer:
|
||
|
||
configure: error: conditional "HAVE_GST_CHECK" was never defined.
|
||
Usually this means the macro was only invoked conditionally.
|
||
|
||
https://bugs.freedesktop.org/show_bug.cgi?id=90801
|
||
|
||
commit d3a7b315ec708ac9ecb8df53bcc8d108016bd508
|
||
Author: Philip Withnall <philip.withnall@collabora.co.uk>
|
||
Date: Fri May 8 10:13:39 2015 +0100
|
||
|
||
build: Auto-generate win32 .def file from libnice.sym
|
||
|
||
We’ve neglected to manually update this file once too often — it’s been
|
||
out of date for important new symbols (for example,
|
||
nice_agent_get_io_stream()) since at least 0.1.11.
|
||
|
||
Since the format is a simple extension of libnice.sym, we might as well
|
||
automatically generate it at dist time.
|
||
|
||
commit 6a8c63219c632c27707267b6510dca096c6fd511
|
||
Author: Youness Alaoui <kakaroto@kakaroto.homelinux.net>
|
||
Date: Tue May 5 15:07:10 2015 -0400
|
||
|
||
Removing no-op assignment
|
||
|
||
commit 91a7b9324244844baf35d8fcef019a4ea3872d30
|
||
Author: Youness Alaoui <kakaroto@kakaroto.homelinux.net>
|
||
Date: Tue May 5 15:00:30 2015 -0400
|
||
|
||
Do not compare scope for IPv6 address when scope is 0
|
||
|
||
This caused issues with thinking local host candidates were peer-reflexive
|
||
candidates because the nice_address_equal would fail since the scope
|
||
would be 6 (or some other value) but locally created NiceAddress from
|
||
a stun response would have the scope set to 0.
|
||
We ignore the scope when comparing ipv6 candidates when scope is 0
|
||
to avoid these kinds of issues.
|
||
Thanks to ikonst_ for finding these issues
|
||
|
||
commit 93862c1e1940618e06143d4788f54bffd4d1c5da
|
||
Author: Youness Alaoui <kakaroto@kakaroto.homelinux.net>
|
||
Date: Tue May 5 14:24:15 2015 -0400
|
||
|
||
Do not update a remote candidate's type
|
||
|
||
When adding a remote candidate, if it's the same ip:port, we should
|
||
also check its type, otherwise it's a new candidate. We can't allow
|
||
a candidate type to be updated. This caused issues to ikonst_ on IRC
|
||
where for some reason a host candidate appeared as both host and prflx
|
||
and the update caused a remote host candidate to be updated to prflx
|
||
causing a crash when the sockptr was being accessed.
|
||
|
||
commit 7b7d2d986876fc53a23af7b516d78f82f2a546e9
|
||
Author: Philip Withnall <philip@tecnocode.co.uk>
|
||
Date: Sun May 3 16:05:30 2015 +0100
|
||
|
||
agent: Remove unnecessary NULL check
|
||
|
||
With the changes in commit 483bdcf8, @name is now guaranteed to be
|
||
non-NULL. Spotted by Coverity.
|
||
|
||
CID: #109878
|
||
diff --git a/.arcconfig b/.arcconfig
|
||
new file mode 100644
|
||
index 0000000..ba3d1ea
|
||
--- /dev/null
|
||
+++ b/.arcconfig
|
||
@@ -0,0 +1,6 @@
|
||
+{
|
||
+ "phabricator.uri" : "https:\/\/phabricator.freedesktop.org\/",
|
||
+ "history.immutable" : true,
|
||
+ "project.name" : "libnice",
|
||
+ "repository.callsign" : "LIBNICE"
|
||
+}
|
||
diff --git a/Makefile.am b/Makefile.am
|
||
index 432a14d..896c751 100644
|
||
--- a/Makefile.am
|
||
+++ b/Makefile.am
|
||
@@ -33,6 +33,7 @@ EXTRA_DIST = \
|
||
scripts/lcov.sh \
|
||
scripts/valgrind.sh \
|
||
win32 \
|
||
+ win32/vs9/libnice.def \
|
||
m4/introspection.m4
|
||
|
||
MAINTAINERCLEANFILES = ar-lib
|
||
@@ -41,6 +42,22 @@ dist_check_SCRIPTS = \
|
||
scripts/check-symbols.sh \
|
||
scripts/make-symbol-list.sh
|
||
|
||
+# Generate the win32 DLL symbol export file.
|
||
+# The stun_*() symbols at the end have historically been exported on Windows
|
||
+# but not Linux, for no particular reason. They can’t be removed without
|
||
+# breaking ABI. FIXME: Remove them when we next break ABI.
|
||
+win32/vs9/libnice.def: nice/libnice.sym
|
||
+ $(AM_V_GEN)(echo "LIBRARY libnice"; \
|
||
+ echo ""; \
|
||
+ echo "EXPORTS"; \
|
||
+ echo ""; \
|
||
+ cat $<; \
|
||
+ echo "stun_debug"; \
|
||
+ echo "stun_debug_bytes"; \
|
||
+ echo "stun_hash_creds") > $@
|
||
+
|
||
+CLEANFILES += win32/vs9/libnice.def
|
||
+
|
||
lcov:
|
||
find -name '*.gcda' -delete
|
||
$(MAKE) $(AM_MAKEFLAGS) check
|
||
diff --git a/agent/address.c b/agent/address.c
|
||
index a8d9c76..3c20220 100644
|
||
--- a/agent/address.c
|
||
+++ b/agent/address.c
|
||
@@ -51,7 +51,6 @@
|
||
#include "address.h"
|
||
|
||
#ifdef G_OS_WIN32
|
||
-#define inet_pton inet_pton_win32
|
||
#define inet_ntop inet_ntop_win32
|
||
|
||
/* Defined in recent versions of mingw:
|
||
@@ -86,36 +85,6 @@ inet_ntop_win32 (int af, const void *src, char *dst, socklen_t cnt)
|
||
return NULL;
|
||
}
|
||
|
||
-static int
|
||
-inet_pton_win32(int af, const char *src, void *dst)
|
||
-{
|
||
- struct addrinfo hints, *res, *ressave;
|
||
-
|
||
- memset(&hints, 0, sizeof(struct addrinfo));
|
||
- hints.ai_family = af;
|
||
-
|
||
- if (getaddrinfo(src, NULL, &hints, &res) != 0) {
|
||
- return 0;
|
||
- }
|
||
-
|
||
- ressave = res;
|
||
-
|
||
- while (res) {
|
||
- if( res->ai_addr->sa_family == AF_INET) {
|
||
- memcpy(dst, &((struct sockaddr_in *) res->ai_addr)->sin_addr,
|
||
- sizeof(struct in_addr));
|
||
- res = res->ai_next;
|
||
- } else if(res->ai_addr->sa_family == AF_INET6) {
|
||
- memcpy(dst, &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr,
|
||
- sizeof(struct in_addr6));
|
||
- res = res->ai_next;
|
||
- }
|
||
- }
|
||
-
|
||
- freeaddrinfo(ressave);
|
||
- return 1;
|
||
-}
|
||
-
|
||
#endif
|
||
|
||
|
||
@@ -297,7 +266,8 @@ nice_address_equal (const NiceAddress *a, const NiceAddress *b)
|
||
case AF_INET6:
|
||
return IN6_ARE_ADDR_EQUAL (&a->s.ip6.sin6_addr, &b->s.ip6.sin6_addr)
|
||
&& (a->s.ip6.sin6_port == b->s.ip6.sin6_port)
|
||
- && (a->s.ip6.sin6_scope_id == b->s.ip6.sin6_scope_id);
|
||
+ && (a->s.ip6.sin6_scope_id == 0 || b->s.ip6.sin6_scope_id == 0 ||
|
||
+ (a->s.ip6.sin6_scope_id == b->s.ip6.sin6_scope_id));
|
||
|
||
default:
|
||
g_return_val_if_reached (FALSE);
|
||
@@ -412,7 +382,8 @@ nice_address_equal_no_port (const NiceAddress *a, const NiceAddress *b)
|
||
|
||
case AF_INET6:
|
||
return IN6_ARE_ADDR_EQUAL (&a->s.ip6.sin6_addr, &b->s.ip6.sin6_addr)
|
||
- && (a->s.ip6.sin6_scope_id == b->s.ip6.sin6_scope_id);
|
||
+ && (a->s.ip6.sin6_scope_id == 0 || b->s.ip6.sin6_scope_id == 0 ||
|
||
+ (a->s.ip6.sin6_scope_id == b->s.ip6.sin6_scope_id));
|
||
|
||
default:
|
||
g_return_val_if_reached (FALSE);
|
||
diff --git a/agent/agent-priv.h b/agent/agent-priv.h
|
||
index c413bc1..d66a9ef 100644
|
||
--- a/agent/agent-priv.h
|
||
+++ b/agent/agent-priv.h
|
||
@@ -130,6 +130,7 @@ struct _NiceAgent
|
||
gboolean controlling_mode; /* property: controlling-mode */
|
||
guint timer_ta; /* property: timer Ta */
|
||
guint max_conn_checks; /* property: max connectivity checks */
|
||
+ gboolean force_relay; /* property: force relay */
|
||
|
||
GSList *local_addresses; /* list of NiceAddresses for local
|
||
interfaces */
|
||
@@ -139,6 +140,7 @@ struct _NiceAgent
|
||
guint next_stream_id; /* id of next created candidate */
|
||
NiceRNG *rng; /* random number generator */
|
||
GSList *discovery_list; /* list of CandidateDiscovery items */
|
||
+ GSList *triggered_check_queue; /* pairs in the triggered check list */
|
||
guint discovery_unsched_items; /* number of discovery items unscheduled */
|
||
GSource *discovery_timer_source; /* source of discovery timer */
|
||
GSource *conncheck_timer_source; /* source of conncheck timer */
|
||
@@ -171,10 +173,10 @@ agent_find_component (
|
||
NiceAgent *agent,
|
||
guint stream_id,
|
||
guint component_id,
|
||
- Stream **stream,
|
||
- Component **component);
|
||
+ NiceStream **stream,
|
||
+ NiceComponent **component) G_GNUC_WARN_UNUSED_RESULT;
|
||
|
||
-Stream *agent_find_stream (NiceAgent *agent, guint stream_id);
|
||
+NiceStream *agent_find_stream (NiceAgent *agent, guint stream_id);
|
||
|
||
void agent_gathering_done (NiceAgent *agent);
|
||
void agent_signal_gathering_done (NiceAgent *agent);
|
||
@@ -202,7 +204,7 @@ void agent_signal_new_candidate (
|
||
|
||
void agent_signal_new_remote_candidate (NiceAgent *agent, NiceCandidate *candidate);
|
||
|
||
-void agent_signal_initial_binding_request_received (NiceAgent *agent, Stream *stream);
|
||
+void agent_signal_initial_binding_request_received (NiceAgent *agent, NiceStream *stream);
|
||
|
||
guint64 agent_candidate_pair_priority (NiceAgent *agent, NiceCandidate *local, NiceCandidate *remote);
|
||
|
||
@@ -220,6 +222,8 @@ void nice_agent_init_stun_agent (NiceAgent *agent, StunAgent *stun_agent);
|
||
|
||
void _priv_set_socket_tos (NiceAgent *agent, NiceSocket *sock, gint tos);
|
||
|
||
+void _tcp_sock_is_writable (NiceSocket *sock, gpointer user_data);
|
||
+
|
||
gboolean
|
||
component_io_cb (
|
||
GSocket *gsocket,
|
||
@@ -274,10 +278,14 @@ void nice_debug_init (void);
|
||
|
||
#ifdef NDEBUG
|
||
static inline gboolean nice_debug_is_enabled (void) { return FALSE; }
|
||
+static inline gboolean nice_debug_is_verbose (void) { return FALSE; }
|
||
static inline void nice_debug (const char *fmt, ...) { }
|
||
+static inline void nice_debug_verbose (const char *fmt, ...) { }
|
||
#else
|
||
gboolean nice_debug_is_enabled (void);
|
||
+gboolean nice_debug_is_verbose (void);
|
||
void nice_debug (const char *fmt, ...) G_GNUC_PRINTF (1, 2);
|
||
+void nice_debug_verbose (const char *fmt, ...) G_GNUC_PRINTF (1, 2);
|
||
#endif
|
||
|
||
#endif /*_NICE_AGENT_PRIV_H */
|
||
diff --git a/agent/agent.c b/agent/agent.c
|
||
index 259fdc9..f6c7a36 100644
|
||
--- a/agent/agent.c
|
||
+++ b/agent/agent.c
|
||
@@ -86,6 +86,7 @@
|
||
static void
|
||
nice_debug_input_message_composition (const NiceInputMessage *messages,
|
||
guint n_messages);
|
||
+static const gchar *_cand_type_to_sdp (NiceCandidateType type);
|
||
|
||
G_DEFINE_TYPE (NiceAgent, nice_agent, G_TYPE_OBJECT);
|
||
|
||
@@ -110,7 +111,8 @@ enum
|
||
PROP_ICE_UDP,
|
||
PROP_ICE_TCP,
|
||
PROP_BYTESTREAM_TCP,
|
||
- PROP_KEEPALIVE_CONNCHECK
|
||
+ PROP_KEEPALIVE_CONNCHECK,
|
||
+ PROP_FORCE_RELAY,
|
||
};
|
||
|
||
|
||
@@ -133,11 +135,7 @@ enum
|
||
|
||
static guint signals[N_SIGNALS];
|
||
|
||
-#if GLIB_CHECK_VERSION(2,31,8)
|
||
static GMutex agent_mutex; /* Mutex used for thread-safe lib */
|
||
-#else
|
||
-static GStaticMutex agent_mutex = G_STATIC_MUTEX_INIT;
|
||
-#endif
|
||
|
||
static void priv_stop_upnp (NiceAgent *agent);
|
||
|
||
@@ -148,7 +146,7 @@ static void pseudo_tcp_socket_closed (PseudoTcpSocket *sock, guint32 err,
|
||
gpointer user_data);
|
||
static PseudoTcpWriteResult pseudo_tcp_socket_write_packet (PseudoTcpSocket *sock,
|
||
const gchar *buffer, guint32 len, gpointer user_data);
|
||
-static void adjust_tcp_clock (NiceAgent *agent, Stream *stream, Component *component);
|
||
+static void adjust_tcp_clock (NiceAgent *agent, NiceStream *stream, NiceComponent *component);
|
||
|
||
static void nice_agent_dispose (GObject *object);
|
||
static void nice_agent_get_property (GObject *object,
|
||
@@ -156,7 +154,6 @@ static void nice_agent_get_property (GObject *object,
|
||
static void nice_agent_set_property (GObject *object,
|
||
guint property_id, const GValue *value, GParamSpec *pspec);
|
||
|
||
-#if GLIB_CHECK_VERSION(2,31,8)
|
||
void agent_lock (void)
|
||
{
|
||
g_mutex_lock (&agent_mutex);
|
||
@@ -167,19 +164,6 @@ void agent_unlock (void)
|
||
g_mutex_unlock (&agent_mutex);
|
||
}
|
||
|
||
-#else
|
||
-void agent_lock(void)
|
||
-{
|
||
- g_static_mutex_lock (&agent_mutex);
|
||
-}
|
||
-
|
||
-void agent_unlock(void)
|
||
-{
|
||
- g_static_mutex_unlock (&agent_mutex);
|
||
-}
|
||
-
|
||
-#endif
|
||
-
|
||
static GType _nice_agent_stream_ids_get_type (void);
|
||
|
||
G_DEFINE_POINTER_TYPE (_NiceAgentStreamIds, _nice_agent_stream_ids);
|
||
@@ -314,13 +298,13 @@ agent_to_turn_socket_compatibility (NiceAgent *agent)
|
||
NICE_TURN_SOCKET_COMPATIBILITY_RFC5766;
|
||
}
|
||
|
||
-Stream *agent_find_stream (NiceAgent *agent, guint stream_id)
|
||
+NiceStream *agent_find_stream (NiceAgent *agent, guint stream_id)
|
||
{
|
||
GSList *i;
|
||
|
||
for (i = agent->streams; i; i = i->next)
|
||
{
|
||
- Stream *s = i->data;
|
||
+ NiceStream *s = i->data;
|
||
|
||
if (s->id == stream_id)
|
||
return s;
|
||
@@ -335,18 +319,18 @@ agent_find_component (
|
||
NiceAgent *agent,
|
||
guint stream_id,
|
||
guint component_id,
|
||
- Stream **stream,
|
||
- Component **component)
|
||
+ NiceStream **stream,
|
||
+ NiceComponent **component)
|
||
{
|
||
- Stream *s;
|
||
- Component *c;
|
||
+ NiceStream *s;
|
||
+ NiceComponent *c;
|
||
|
||
s = agent_find_stream (agent, stream_id);
|
||
|
||
if (s == NULL)
|
||
return FALSE;
|
||
|
||
- c = stream_find_component_by_id (s, component_id);
|
||
+ c = nice_stream_find_component_by_id (s, component_id);
|
||
|
||
if (c == NULL)
|
||
return FALSE;
|
||
@@ -706,6 +690,24 @@ nice_agent_class_init (NiceAgentClass *klass)
|
||
FALSE,
|
||
G_PARAM_READWRITE));
|
||
|
||
+ /**
|
||
+ * NiceAgent:force-relay
|
||
+ *
|
||
+ * Force all traffic to go through a relay for added privacy, this
|
||
+ * allows hiding the local IP address. When this is enabled, so
|
||
+ * local candidates are available before relay servers have been set
|
||
+ * with nice_agent_set_relay_info().
|
||
+ *
|
||
+ * Since: UNRELEASED
|
||
+ */
|
||
+ g_object_class_install_property (gobject_class, PROP_FORCE_RELAY,
|
||
+ g_param_spec_boolean (
|
||
+ "force-relay",
|
||
+ "Force Relay",
|
||
+ "Force all traffic to go through a relay for added privacy.",
|
||
+ FALSE,
|
||
+ G_PARAM_READWRITE));
|
||
+
|
||
/* install signals */
|
||
|
||
/**
|
||
@@ -713,9 +715,12 @@ nice_agent_class_init (NiceAgentClass *klass)
|
||
* @agent: The #NiceAgent object
|
||
* @stream_id: The ID of the stream
|
||
* @component_id: The ID of the component
|
||
- * @state: The #NiceComponentState of the component
|
||
+ * @state: The new #NiceComponentState of the component
|
||
+ *
|
||
+ * This signal is fired whenever a component’s state changes. There are many
|
||
+ * valid state transitions.
|
||
*
|
||
- * This signal is fired whenever a component's state changes
|
||
+ * ![State transition diagram](states.png)
|
||
*/
|
||
signals[SIGNAL_COMPONENT_STATE_CHANGED] =
|
||
g_signal_new (
|
||
@@ -1178,6 +1183,10 @@ nice_agent_get_property (
|
||
g_value_set_boolean (value, agent->keepalive_conncheck);
|
||
break;
|
||
|
||
+ case PROP_FORCE_RELAY:
|
||
+ g_value_set_boolean (value, agent->force_relay);
|
||
+ break;
|
||
+
|
||
default:
|
||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||
}
|
||
@@ -1231,11 +1240,11 @@ nice_agent_reset_all_stun_agents (NiceAgent *agent, gboolean only_software)
|
||
|
||
for (stream_item = agent->streams; stream_item;
|
||
stream_item = stream_item->next) {
|
||
- Stream *stream = stream_item->data;
|
||
+ NiceStream *stream = stream_item->data;
|
||
|
||
for (component_item = stream->components; component_item;
|
||
component_item = component_item->next) {
|
||
- Component *component = component_item->data;
|
||
+ NiceComponent *component = component_item->data;
|
||
|
||
if (only_software)
|
||
stun_agent_set_software (&component->stun_agent,
|
||
@@ -1361,6 +1370,10 @@ nice_agent_set_property (
|
||
agent->keepalive_conncheck = g_value_get_boolean (value);
|
||
break;
|
||
|
||
+ case PROP_FORCE_RELAY:
|
||
+ agent->force_relay = g_value_get_boolean (value);
|
||
+ break;
|
||
+
|
||
default:
|
||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||
}
|
||
@@ -1371,7 +1384,7 @@ nice_agent_set_property (
|
||
|
||
|
||
static void
|
||
- agent_signal_socket_writable (NiceAgent *agent, Component *component)
|
||
+ agent_signal_socket_writable (NiceAgent *agent, NiceComponent *component)
|
||
{
|
||
g_cancellable_cancel (component->tcp_writable_cancellable);
|
||
|
||
@@ -1380,7 +1393,7 @@ static void
|
||
}
|
||
|
||
static void
|
||
-pseudo_tcp_socket_create (NiceAgent *agent, Stream *stream, Component *component)
|
||
+pseudo_tcp_socket_create (NiceAgent *agent, NiceStream *stream, NiceComponent *component)
|
||
{
|
||
PseudoTcpCallbacks tcp_callbacks = {component,
|
||
pseudo_tcp_socket_opened,
|
||
@@ -1394,8 +1407,8 @@ pseudo_tcp_socket_create (NiceAgent *agent, Stream *stream, Component *component
|
||
agent, component->id);
|
||
}
|
||
|
||
-static void priv_pseudo_tcp_error (NiceAgent *agent, Stream *stream,
|
||
- Component *component)
|
||
+static void priv_pseudo_tcp_error (NiceAgent *agent, NiceStream *stream,
|
||
+ NiceComponent *component)
|
||
{
|
||
if (component->tcp_writable_cancellable) {
|
||
g_cancellable_cancel (component->tcp_writable_cancellable);
|
||
@@ -1405,7 +1418,7 @@ static void priv_pseudo_tcp_error (NiceAgent *agent, Stream *stream,
|
||
if (component->tcp) {
|
||
agent_signal_component_state_change (agent, stream->id,
|
||
component->id, NICE_COMPONENT_STATE_FAILED);
|
||
- component_detach_all_sockets (component);
|
||
+ nice_component_detach_all_sockets (component);
|
||
pseudo_tcp_socket_close (component->tcp, TRUE);
|
||
}
|
||
|
||
@@ -1419,9 +1432,9 @@ static void priv_pseudo_tcp_error (NiceAgent *agent, Stream *stream,
|
||
static void
|
||
pseudo_tcp_socket_opened (PseudoTcpSocket *sock, gpointer user_data)
|
||
{
|
||
- Component *component = user_data;
|
||
+ NiceComponent *component = user_data;
|
||
NiceAgent *agent = component->agent;
|
||
- Stream *stream = component->stream;
|
||
+ NiceStream *stream = component->stream;
|
||
|
||
nice_debug ("Agent %p: s%d:%d pseudo Tcp socket Opened", agent,
|
||
stream->id, component->id);
|
||
@@ -1533,7 +1546,7 @@ pseudo_tcp_socket_recv_messages (PseudoTcpSocket *self,
|
||
(gchar *) buffer->buffer + iter->offset,
|
||
buffer->size - iter->offset);
|
||
|
||
- nice_debug ("%s: Received %" G_GSSIZE_FORMAT " bytes into "
|
||
+ nice_debug_verbose ("%s: Received %" G_GSSIZE_FORMAT " bytes into "
|
||
"buffer %p (offset %" G_GSIZE_FORMAT ", length %" G_GSIZE_FORMAT
|
||
").", G_STRFUNC, len, buffer->buffer, iter->offset, buffer->size);
|
||
|
||
@@ -1580,25 +1593,25 @@ done:
|
||
static void
|
||
pseudo_tcp_socket_readable (PseudoTcpSocket *sock, gpointer user_data)
|
||
{
|
||
- Component *component = user_data;
|
||
+ NiceComponent *component = user_data;
|
||
NiceAgent *agent = component->agent;
|
||
- Stream *stream = component->stream;
|
||
+ NiceStream *stream = component->stream;
|
||
gboolean has_io_callback;
|
||
guint stream_id = stream->id;
|
||
guint component_id = component->id;
|
||
|
||
g_object_ref (agent);
|
||
|
||
- nice_debug ("Agent %p: s%d:%d pseudo Tcp socket readable", agent,
|
||
+ nice_debug_verbose ("Agent %p: s%d:%d pseudo Tcp socket readable", agent,
|
||
stream->id, component->id);
|
||
|
||
component->tcp_readable = TRUE;
|
||
|
||
- has_io_callback = component_has_io_callback (component);
|
||
+ has_io_callback = nice_component_has_io_callback (component);
|
||
|
||
/* Only dequeue pseudo-TCP data if we can reliably inform the client. The
|
||
* agent lock is held here, so has_io_callback can only change during
|
||
- * component_emit_io_callback(), after which it’s re-queried. This ensures
|
||
+ * nice_component_emit_io_callback(), after which it’s re-queried. This ensures
|
||
* no data loss of packets already received and dequeued. */
|
||
if (has_io_callback) {
|
||
do {
|
||
@@ -1641,7 +1654,7 @@ pseudo_tcp_socket_readable (PseudoTcpSocket *sock, gpointer user_data)
|
||
break;
|
||
}
|
||
|
||
- component_emit_io_callback (component, buf, len);
|
||
+ nice_component_emit_io_callback (component, buf, len);
|
||
|
||
if (!agent_find_component (agent, stream_id, component_id,
|
||
&stream, &component)) {
|
||
@@ -1653,7 +1666,7 @@ pseudo_tcp_socket_readable (PseudoTcpSocket *sock, gpointer user_data)
|
||
goto out;
|
||
}
|
||
|
||
- has_io_callback = component_has_io_callback (component);
|
||
+ has_io_callback = nice_component_has_io_callback (component);
|
||
} while (has_io_callback);
|
||
} else if (component->recv_messages != NULL) {
|
||
gint n_valid_messages;
|
||
@@ -1667,7 +1680,7 @@ pseudo_tcp_socket_readable (PseudoTcpSocket *sock, gpointer user_data)
|
||
component->recv_messages, component->n_recv_messages,
|
||
&component->recv_messages_iter, &child_error);
|
||
|
||
- nice_debug ("%s: Client buffers case: Received %d valid messages:",
|
||
+ nice_debug_verbose ("%s: Client buffers case: Received %d valid messages:",
|
||
G_STRFUNC, n_valid_messages);
|
||
nice_debug_input_message_composition (component->recv_messages,
|
||
component->n_recv_messages);
|
||
@@ -1700,17 +1713,16 @@ pseudo_tcp_socket_readable (PseudoTcpSocket *sock, gpointer user_data)
|
||
out:
|
||
|
||
g_object_unref (agent);
|
||
-
|
||
}
|
||
|
||
static void
|
||
pseudo_tcp_socket_writable (PseudoTcpSocket *sock, gpointer user_data)
|
||
{
|
||
- Component *component = user_data;
|
||
+ NiceComponent *component = user_data;
|
||
NiceAgent *agent = component->agent;
|
||
- Stream *stream = component->stream;
|
||
+ NiceStream *stream = component->stream;
|
||
|
||
- nice_debug ("Agent %p: s%d:%d pseudo Tcp socket writable", agent,
|
||
+ nice_debug_verbose ("Agent %p: s%d:%d pseudo Tcp socket writable", agent,
|
||
stream->id, component->id);
|
||
|
||
agent_signal_socket_writable (agent, component);
|
||
@@ -1720,9 +1732,9 @@ static void
|
||
pseudo_tcp_socket_closed (PseudoTcpSocket *sock, guint32 err,
|
||
gpointer user_data)
|
||
{
|
||
- Component *component = user_data;
|
||
+ NiceComponent *component = user_data;
|
||
NiceAgent *agent = component->agent;
|
||
- Stream *stream = component->stream;
|
||
+ NiceStream *stream = component->stream;
|
||
|
||
nice_debug ("Agent %p: s%d:%d pseudo Tcp socket closed. "
|
||
"Calling priv_pseudo_tcp_error().", agent, stream->id, component->id);
|
||
@@ -1734,7 +1746,7 @@ static PseudoTcpWriteResult
|
||
pseudo_tcp_socket_write_packet (PseudoTcpSocket *psocket,
|
||
const gchar *buffer, guint32 len, gpointer user_data)
|
||
{
|
||
- Component *component = user_data;
|
||
+ NiceComponent *component = user_data;
|
||
|
||
if (component->selected_pair.local != NULL) {
|
||
NiceSocket *sock;
|
||
@@ -1747,7 +1759,7 @@ pseudo_tcp_socket_write_packet (PseudoTcpSocket *psocket,
|
||
gchar tmpbuf[INET6_ADDRSTRLEN];
|
||
nice_address_to_string (addr, tmpbuf);
|
||
|
||
- nice_debug (
|
||
+ nice_debug_verbose (
|
||
"Agent %p : s%d:%d: sending %d bytes on socket %p (FD %d) to [%s]:%d",
|
||
component->agent, component->stream->id, component->id, len,
|
||
sock->fileno, g_socket_get_fd (sock->fileno), tmpbuf,
|
||
@@ -1775,8 +1787,8 @@ pseudo_tcp_socket_write_packet (PseudoTcpSocket *psocket,
|
||
static gboolean
|
||
notify_pseudo_tcp_socket_clock (gpointer user_data)
|
||
{
|
||
- Component *component = user_data;
|
||
- Stream *stream;
|
||
+ NiceComponent *component = user_data;
|
||
+ NiceStream *stream;
|
||
NiceAgent *agent;
|
||
|
||
agent_lock();
|
||
@@ -1800,7 +1812,7 @@ notify_pseudo_tcp_socket_clock (gpointer user_data)
|
||
}
|
||
|
||
static void
|
||
-adjust_tcp_clock (NiceAgent *agent, Stream *stream, Component *component)
|
||
+adjust_tcp_clock (NiceAgent *agent, NiceStream *stream, NiceComponent *component)
|
||
{
|
||
if (!pseudo_tcp_socket_is_closed (component->tcp)) {
|
||
guint64 timeout = component->last_clock_timeout;
|
||
@@ -1809,13 +1821,7 @@ adjust_tcp_clock (NiceAgent *agent, Stream *stream, Component *component)
|
||
if (timeout != component->last_clock_timeout) {
|
||
component->last_clock_timeout = timeout;
|
||
if (component->tcp_clock) {
|
||
-#if GLIB_CHECK_VERSION (2, 36, 0)
|
||
g_source_set_ready_time (component->tcp_clock, timeout * 1000);
|
||
-#else
|
||
- g_source_destroy (component->tcp_clock);
|
||
- g_source_unref (component->tcp_clock);
|
||
- component->tcp_clock = NULL;
|
||
-#endif
|
||
}
|
||
if (!component->tcp_clock) {
|
||
long interval = timeout - (guint32) (g_get_monotonic_time () / 1000);
|
||
@@ -1837,19 +1843,19 @@ adjust_tcp_clock (NiceAgent *agent, Stream *stream, Component *component)
|
||
}
|
||
}
|
||
|
||
-static void
|
||
+void
|
||
_tcp_sock_is_writable (NiceSocket *sock, gpointer user_data)
|
||
{
|
||
- Component *component = user_data;
|
||
+ NiceComponent *component = user_data;
|
||
NiceAgent *agent = component->agent;
|
||
- Stream *stream = component->stream;
|
||
+ NiceStream *stream = component->stream;
|
||
|
||
agent_lock ();
|
||
|
||
/* Don't signal writable if the socket that has become writable is not
|
||
* the selected pair */
|
||
if (component->selected_pair.local == NULL ||
|
||
- component->selected_pair.local->sockptr != sock) {
|
||
+ !nice_socket_is_based_on (component->selected_pair.local->sockptr, sock)) {
|
||
agent_unlock ();
|
||
return;
|
||
}
|
||
@@ -1883,12 +1889,17 @@ void agent_gathering_done (NiceAgent *agent)
|
||
GSList *i, *j, *k, *l, *m;
|
||
|
||
for (i = agent->streams; i; i = i->next) {
|
||
- Stream *stream = i->data;
|
||
+ NiceStream *stream = i->data;
|
||
for (j = stream->components; j; j = j->next) {
|
||
- Component *component = j->data;
|
||
+ NiceComponent *component = j->data;
|
||
|
||
for (k = component->local_candidates; k; k = k->next) {
|
||
NiceCandidate *local_candidate = k->data;
|
||
+
|
||
+ if (agent->force_relay &&
|
||
+ local_candidate->type != NICE_CANDIDATE_TYPE_RELAYED)
|
||
+ continue;
|
||
+
|
||
if (nice_debug_is_enabled ()) {
|
||
gchar tmpbuf[INET6_ADDRSTRLEN];
|
||
nice_address_to_string (&local_candidate->addr, tmpbuf);
|
||
@@ -1933,7 +1944,7 @@ void agent_signal_gathering_done (NiceAgent *agent)
|
||
GSList *i;
|
||
|
||
for (i = agent->streams; i; i = i->next) {
|
||
- Stream *stream = i->data;
|
||
+ NiceStream *stream = i->data;
|
||
if (stream->gathering) {
|
||
stream->gathering = FALSE;
|
||
agent_queue_signal (agent, signals[SIGNAL_CANDIDATE_GATHERING_DONE],
|
||
@@ -1942,7 +1953,9 @@ void agent_signal_gathering_done (NiceAgent *agent)
|
||
}
|
||
}
|
||
|
||
-void agent_signal_initial_binding_request_received (NiceAgent *agent, Stream *stream)
|
||
+void
|
||
+agent_signal_initial_binding_request_received (NiceAgent *agent,
|
||
+ NiceStream *stream)
|
||
{
|
||
if (stream->initial_binding_request_received != TRUE) {
|
||
stream->initial_binding_request_received = TRUE;
|
||
@@ -1957,8 +1970,8 @@ void agent_signal_initial_binding_request_received (NiceAgent *agent, Stream *st
|
||
*
|
||
* Must be called with the agent lock held. */
|
||
static void
|
||
-process_queued_tcp_packets (NiceAgent *agent, Stream *stream,
|
||
- Component *component)
|
||
+process_queued_tcp_packets (NiceAgent *agent, NiceStream *stream,
|
||
+ NiceComponent *component)
|
||
{
|
||
GOutputVector *vec;
|
||
guint stream_id = stream->id;
|
||
@@ -1972,7 +1985,7 @@ process_queued_tcp_packets (NiceAgent *agent, Stream *stream,
|
||
return;
|
||
}
|
||
|
||
- nice_debug ("%s: Sending outstanding packets for agent %p.", G_STRFUNC,
|
||
+ nice_debug_verbose ("%s: Sending outstanding packets for agent %p.", G_STRFUNC,
|
||
agent);
|
||
|
||
while ((vec = g_queue_peek_head (&component->queued_tcp_packets)) != NULL) {
|
||
@@ -2011,8 +2024,8 @@ process_queued_tcp_packets (NiceAgent *agent, Stream *stream,
|
||
void agent_signal_new_selected_pair (NiceAgent *agent, guint stream_id,
|
||
guint component_id, NiceCandidate *lcandidate, NiceCandidate *rcandidate)
|
||
{
|
||
- Component *component;
|
||
- Stream *stream;
|
||
+ NiceComponent *component;
|
||
+ NiceStream *stream;
|
||
|
||
if (!agent_find_component (agent, stream_id, component_id,
|
||
&stream, &component))
|
||
@@ -2122,28 +2135,67 @@ nice_component_state_to_string (NiceComponentState state)
|
||
}
|
||
}
|
||
|
||
-void agent_signal_component_state_change (NiceAgent *agent, guint stream_id, guint component_id, NiceComponentState state)
|
||
+void agent_signal_component_state_change (NiceAgent *agent, guint stream_id, guint component_id, NiceComponentState new_state)
|
||
{
|
||
- Component *component;
|
||
- Stream *stream;
|
||
+ NiceComponentState old_state;
|
||
+ NiceComponent *component;
|
||
+ NiceStream *stream;
|
||
+
|
||
+ g_return_if_fail (new_state < NICE_COMPONENT_STATE_LAST);
|
||
|
||
if (!agent_find_component (agent, stream_id, component_id,
|
||
&stream, &component))
|
||
return;
|
||
|
||
- if (component->state != state && state < NICE_COMPONENT_STATE_LAST) {
|
||
- nice_debug ("Agent %p : stream %u component %u STATE-CHANGE %s -> %s.", agent,
|
||
- stream_id, component_id, nice_component_state_to_string (component->state),
|
||
- nice_component_state_to_string (state));
|
||
+ /* Validate the state change. */
|
||
+ old_state = component->state;
|
||
|
||
- component->state = state;
|
||
+ if (new_state == old_state) {
|
||
+ return;
|
||
+ }
|
||
|
||
- if (agent->reliable)
|
||
- process_queued_tcp_packets (agent, stream, component);
|
||
+ nice_debug ("Agent %p : stream %u component %u STATE-CHANGE %s -> %s.", agent,
|
||
+ stream_id, component_id, nice_component_state_to_string (old_state),
|
||
+ nice_component_state_to_string (new_state));
|
||
+
|
||
+ /* Check whether it’s a valid state transition. */
|
||
+#define TRANSITION(OLD, NEW) \
|
||
+ (old_state == NICE_COMPONENT_STATE_##OLD && \
|
||
+ new_state == NICE_COMPONENT_STATE_##NEW)
|
||
+
|
||
+ g_assert (/* Can (almost) always transition to FAILED (including
|
||
+ * DISCONNECTED → FAILED which happens if one component fails
|
||
+ * before another leaves DISCONNECTED): */
|
||
+ TRANSITION (DISCONNECTED, FAILED) ||
|
||
+ TRANSITION (GATHERING, FAILED) ||
|
||
+ TRANSITION (CONNECTING, FAILED) ||
|
||
+ TRANSITION (CONNECTED, FAILED) ||
|
||
+ TRANSITION (READY, FAILED) ||
|
||
+ /* Standard progression towards a ready connection: */
|
||
+ TRANSITION (DISCONNECTED, GATHERING) ||
|
||
+ TRANSITION (GATHERING, CONNECTING) ||
|
||
+ TRANSITION (CONNECTING, CONNECTED) ||
|
||
+ TRANSITION (CONNECTED, READY) ||
|
||
+ /* priv_conn_check_add_for_candidate_pair_matched(): */
|
||
+ TRANSITION (READY, CONNECTED) ||
|
||
+ /* If set_remote_candidates() is called with new candidates after
|
||
+ * reaching FAILED: */
|
||
+ TRANSITION (FAILED, CONNECTING) ||
|
||
+ /* if new relay servers are added to a failed connection */
|
||
+ TRANSITION (FAILED, GATHERING) ||
|
||
+ /* Possible by calling set_remote_candidates() without calling
|
||
+ * nice_agent_gather_candidates(): */
|
||
+ TRANSITION (DISCONNECTED, CONNECTING));
|
||
+
|
||
+#undef TRANSITION
|
||
+
|
||
+ component->state = new_state;
|
||
|
||
- agent_queue_signal (agent, signals[SIGNAL_COMPONENT_STATE_CHANGED],
|
||
- stream_id, component_id, state);
|
||
- }
|
||
+ if (agent->reliable)
|
||
+ process_queued_tcp_packets (agent, stream, component);
|
||
+
|
||
+ agent_queue_signal (agent, signals[SIGNAL_COMPONENT_STATE_CHANGED],
|
||
+ stream_id, component_id, new_state);
|
||
}
|
||
|
||
guint64
|
||
@@ -2158,7 +2210,7 @@ agent_candidate_pair_priority (NiceAgent *agent, NiceCandidate *local, NiceCandi
|
||
static void
|
||
priv_add_new_candidate_discovery_stun (NiceAgent *agent,
|
||
NiceSocket *nicesock, NiceAddress server,
|
||
- Stream *stream, guint component_id)
|
||
+ NiceStream *stream, guint component_id)
|
||
{
|
||
CandidateDiscovery *cdisco;
|
||
|
||
@@ -2171,7 +2223,7 @@ priv_add_new_candidate_discovery_stun (NiceAgent *agent,
|
||
cdisco->nicesock = nicesock;
|
||
cdisco->server = server;
|
||
cdisco->stream = stream;
|
||
- cdisco->component = stream_find_component_by_id (stream, component_id);
|
||
+ cdisco->component = nice_stream_find_component_by_id (stream, component_id);
|
||
cdisco->agent = agent;
|
||
stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
|
||
STUN_COMPATIBILITY_RFC3489,
|
||
@@ -2179,7 +2231,7 @@ priv_add_new_candidate_discovery_stun (NiceAgent *agent,
|
||
agent->compatibility == NICE_COMPATIBILITY_OC2007R2) ?
|
||
STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES : 0);
|
||
|
||
- nice_debug ("Agent %p : Adding new srv-rflx candidate discovery %p\n",
|
||
+ nice_debug ("Agent %p : Adding new srv-rflx candidate discovery %p",
|
||
agent, cdisco);
|
||
|
||
agent->discovery_list = g_slist_append (agent->discovery_list, cdisco);
|
||
@@ -2189,10 +2241,10 @@ priv_add_new_candidate_discovery_stun (NiceAgent *agent,
|
||
static void
|
||
priv_add_new_candidate_discovery_turn (NiceAgent *agent,
|
||
NiceSocket *nicesock, TurnServer *turn,
|
||
- Stream *stream, guint component_id, gboolean turn_tcp)
|
||
+ NiceStream *stream, guint component_id, gboolean turn_tcp)
|
||
{
|
||
CandidateDiscovery *cdisco;
|
||
- Component *component = stream_find_component_by_id (stream, component_id);
|
||
+ NiceComponent *component = nice_stream_find_component_by_id (stream, component_id);
|
||
NiceAddress local_address;
|
||
|
||
/* note: no need to check for redundant candidates, as this is
|
||
@@ -2214,7 +2266,7 @@ priv_add_new_candidate_discovery_turn (NiceAgent *agent,
|
||
new_socket = nice_udp_bsd_socket_new (&addr);
|
||
if (new_socket) {
|
||
_priv_set_socket_tos (agent, new_socket, stream->tos);
|
||
- component_attach_socket (component, new_socket);
|
||
+ nice_component_attach_socket (component, new_socket);
|
||
nicesock = new_socket;
|
||
}
|
||
}
|
||
@@ -2308,14 +2360,14 @@ priv_add_new_candidate_discovery_turn (NiceAgent *agent,
|
||
cdisco->nicesock = nice_udp_turn_over_tcp_socket_new (nicesock,
|
||
agent_to_turn_socket_compatibility (agent));
|
||
|
||
- component_attach_socket (component, cdisco->nicesock);
|
||
+ nice_component_attach_socket (component, cdisco->nicesock);
|
||
}
|
||
|
||
cdisco->turn = turn_server_ref (turn);
|
||
cdisco->server = turn->server;
|
||
|
||
cdisco->stream = stream;
|
||
- cdisco->component = stream_find_component_by_id (stream, component_id);
|
||
+ cdisco->component = nice_stream_find_component_by_id (stream, component_id);
|
||
cdisco->agent = agent;
|
||
|
||
if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
|
||
@@ -2342,7 +2394,7 @@ priv_add_new_candidate_discovery_turn (NiceAgent *agent,
|
||
}
|
||
stun_agent_set_software (&cdisco->stun_agent, agent->software_attribute);
|
||
|
||
- nice_debug ("Agent %p : Adding new relay-rflx candidate discovery %p\n",
|
||
+ nice_debug ("Agent %p : Adding new relay-rflx candidate discovery %p",
|
||
agent, cdisco);
|
||
agent->discovery_list = g_slist_append (agent->discovery_list, cdisco);
|
||
++agent->discovery_unsched_items;
|
||
@@ -2353,7 +2405,7 @@ nice_agent_add_stream (
|
||
NiceAgent *agent,
|
||
guint n_components)
|
||
{
|
||
- Stream *stream;
|
||
+ NiceStream *stream;
|
||
guint ret = 0;
|
||
guint i;
|
||
|
||
@@ -2361,7 +2413,7 @@ nice_agent_add_stream (
|
||
g_return_val_if_fail (n_components >= 1, 0);
|
||
|
||
agent_lock();
|
||
- stream = stream_new (n_components, agent);
|
||
+ stream = nice_stream_new (n_components, agent);
|
||
|
||
agent->streams = g_slist_append (agent->streams, stream);
|
||
stream->id = agent->next_stream_id++;
|
||
@@ -2369,7 +2421,7 @@ nice_agent_add_stream (
|
||
if (agent->reliable) {
|
||
nice_debug ("Agent %p : reliable stream", agent);
|
||
for (i = 0; i < n_components; i++) {
|
||
- Component *component = stream_find_component_by_id (stream, i + 1);
|
||
+ NiceComponent *component = nice_stream_find_component_by_id (stream, i + 1);
|
||
if (component) {
|
||
pseudo_tcp_socket_create (agent, stream, component);
|
||
} else {
|
||
@@ -2378,7 +2430,7 @@ nice_agent_add_stream (
|
||
}
|
||
}
|
||
|
||
- stream_initialize_credentials (stream, agent->rng);
|
||
+ nice_stream_initialize_credentials (stream, agent->rng);
|
||
|
||
ret = stream->id;
|
||
|
||
@@ -2395,8 +2447,8 @@ nice_agent_set_relay_info(NiceAgent *agent,
|
||
NiceRelayType type)
|
||
{
|
||
|
||
- Component *component = NULL;
|
||
- Stream *stream = NULL;
|
||
+ NiceComponent *component = NULL;
|
||
+ NiceStream *stream = NULL;
|
||
gboolean ret = TRUE;
|
||
TurnServer *turn;
|
||
|
||
@@ -2439,7 +2491,9 @@ nice_agent_set_relay_info(NiceAgent *agent,
|
||
NiceCandidate *candidate = i->data;
|
||
|
||
if (candidate->type == NICE_CANDIDATE_TYPE_HOST &&
|
||
- candidate->transport != NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE)
|
||
+ candidate->transport != NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE &&
|
||
+ nice_address_ip_version (&candidate->addr) ==
|
||
+ nice_address_ip_version (&turn->server))
|
||
priv_add_new_candidate_discovery_turn (agent,
|
||
candidate->sockptr, turn, stream, component_id,
|
||
candidate->transport != NICE_CANDIDATE_TRANSPORT_UDP);
|
||
@@ -2547,12 +2601,16 @@ static void _upnp_mapped_external_port (GUPnPSimpleIgd *self, gchar *proto,
|
||
nice_address_set_port (&externaddr, external_port);
|
||
|
||
for (i = agent->streams; i; i = i->next) {
|
||
- Stream *stream = i->data;
|
||
+ NiceStream *stream = i->data;
|
||
for (j = stream->components; j; j = j->next) {
|
||
- Component *component = j->data;
|
||
+ NiceComponent *component = j->data;
|
||
for (k = component->local_candidates; k; k = k->next) {
|
||
NiceCandidate *local_candidate = k->data;
|
||
|
||
+ if (agent->force_relay &&
|
||
+ local_candidate->type != NICE_CANDIDATE_TYPE_RELAYED)
|
||
+ continue;
|
||
+
|
||
if (nice_address_equal (&localaddr, &local_candidate->base_addr)) {
|
||
discovery_add_server_reflexive_candidate (
|
||
agent,
|
||
@@ -2613,7 +2671,7 @@ nice_agent_gather_candidates (
|
||
{
|
||
guint cid;
|
||
GSList *i;
|
||
- Stream *stream;
|
||
+ NiceStream *stream;
|
||
GSList *local_addresses = NULL;
|
||
gboolean ret = TRUE;
|
||
|
||
@@ -2638,13 +2696,10 @@ nice_agent_gather_candidates (
|
||
agent->full_mode ? "ICE-FULL" : "ICE-LITE");
|
||
|
||
#ifdef HAVE_GUPNP
|
||
- if (agent->upnp_enabled && agent->upnp == NULL) {
|
||
+ if (agent->upnp_enabled && agent->upnp == NULL && !agent->force_relay) {
|
||
agent->upnp = gupnp_simple_igd_thread_new ();
|
||
|
||
if (agent->upnp) {
|
||
- agent_timeout_add_with_context (agent, &agent->upnp_timer_source,
|
||
- "UPnP timeout", agent->upnp_timeout, priv_upnp_timeout_cb, agent);
|
||
-
|
||
g_signal_connect (agent->upnp, "mapped-external-port",
|
||
G_CALLBACK (_upnp_mapped_external_port), agent);
|
||
g_signal_connect (agent->upnp, "error-mapping-port",
|
||
@@ -2698,7 +2753,7 @@ nice_agent_gather_candidates (
|
||
#endif
|
||
|
||
for (cid = 1; cid <= stream->n_components; cid++) {
|
||
- Component *component = stream_find_component_by_id (stream, cid);
|
||
+ NiceComponent *component = nice_stream_find_component_by_id (stream, cid);
|
||
enum {
|
||
ADD_HOST_MIN = 0,
|
||
ADD_HOST_UDP = ADD_HOST_MIN,
|
||
@@ -2769,6 +2824,10 @@ nice_agent_gather_candidates (
|
||
" s%d:%d. Invalid interface?", agent, ip, stream->id,
|
||
component->id);
|
||
}
|
||
+ if (agent->local_addresses == NULL) {
|
||
+ /* Ignore when an auto-generated address fails. */
|
||
+ continue;
|
||
+ }
|
||
ret = FALSE;
|
||
goto error;
|
||
}
|
||
@@ -2791,11 +2850,14 @@ nice_agent_gather_candidates (
|
||
0, local_ip, nice_address_get_port (base_addr),
|
||
0, PACKAGE_STRING);
|
||
agent->upnp_mapping = g_slist_prepend (agent->upnp_mapping, base_addr);
|
||
+
|
||
+ agent_timeout_add_with_context (agent, &agent->upnp_timer_source,
|
||
+ "UPnP timeout", agent->upnp_timeout, priv_upnp_timeout_cb, agent);
|
||
}
|
||
#endif
|
||
|
||
/* TODO: Add server-reflexive support for TCP candidates */
|
||
- if (agent->full_mode && agent->stun_server_ip &&
|
||
+ if (agent->full_mode && agent->stun_server_ip && !agent->force_relay &&
|
||
transport == NICE_CANDIDATE_TRANSPORT_UDP) {
|
||
NiceAddress stun_server;
|
||
if (nice_address_set_from_string (&stun_server, agent->stun_server_ip)) {
|
||
@@ -2834,9 +2896,13 @@ nice_agent_gather_candidates (
|
||
/* Only signal the new candidates after we're sure that the gathering was
|
||
* succesfful. But before sending gathering-done */
|
||
for (cid = 1; cid <= stream->n_components; cid++) {
|
||
- Component *component = stream_find_component_by_id (stream, cid);
|
||
+ NiceComponent *component = nice_stream_find_component_by_id (stream, cid);
|
||
for (i = component->local_candidates; i; i = i->next) {
|
||
NiceCandidate *candidate = i->data;
|
||
+
|
||
+ if (agent->force_relay && candidate->type != NICE_CANDIDATE_TYPE_RELAYED)
|
||
+ continue;
|
||
+
|
||
agent_signal_new_candidate (agent, candidate);
|
||
}
|
||
}
|
||
@@ -2863,9 +2929,9 @@ nice_agent_gather_candidates (
|
||
if (ret == FALSE) {
|
||
priv_stop_upnp (agent);
|
||
for (cid = 1; cid <= stream->n_components; cid++) {
|
||
- Component *component = stream_find_component_by_id (stream, cid);
|
||
+ NiceComponent *component = nice_stream_find_component_by_id (stream, cid);
|
||
|
||
- component_free_socket_sources (component);
|
||
+ nice_component_free_socket_sources (component);
|
||
|
||
for (i = component->local_candidates; i; i = i->next) {
|
||
NiceCandidate *candidate = i->data;
|
||
@@ -2938,7 +3004,7 @@ nice_agent_remove_stream (
|
||
|
||
/* note that streams/candidates can be in use by other threads */
|
||
|
||
- Stream *stream;
|
||
+ NiceStream *stream;
|
||
|
||
g_return_if_fail (NICE_IS_AGENT (agent));
|
||
g_return_if_fail (stream_id >= 1);
|
||
@@ -2958,7 +3024,7 @@ nice_agent_remove_stream (
|
||
|
||
/* Remove the stream and signal its removal. */
|
||
agent->streams = g_slist_remove (agent->streams, stream);
|
||
- stream_close (stream);
|
||
+ nice_stream_close (stream);
|
||
|
||
if (!agent->streams)
|
||
priv_remove_keepalive_timer (agent);
|
||
@@ -2971,7 +3037,7 @@ nice_agent_remove_stream (
|
||
/* Actually free the stream. This should be done with the lock released, as
|
||
* it could end up disposing of a NiceIOStream, which tries to take the
|
||
* agent lock itself. */
|
||
- stream_free (stream);
|
||
+ g_object_unref (stream);
|
||
|
||
return;
|
||
}
|
||
@@ -2980,8 +3046,8 @@ NICEAPI_EXPORT void
|
||
nice_agent_set_port_range (NiceAgent *agent, guint stream_id, guint component_id,
|
||
guint min_port, guint max_port)
|
||
{
|
||
- Stream *stream;
|
||
- Component *component;
|
||
+ NiceStream *stream;
|
||
+ NiceComponent *component;
|
||
|
||
g_return_if_fail (NICE_IS_AGENT (agent));
|
||
g_return_if_fail (stream_id >= 1);
|
||
@@ -3033,15 +3099,28 @@ static gboolean priv_add_remote_candidate (
|
||
const gchar *password,
|
||
const gchar *foundation)
|
||
{
|
||
- Component *component;
|
||
+ NiceComponent *component;
|
||
NiceCandidate *candidate;
|
||
|
||
if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
|
||
return FALSE;
|
||
|
||
/* step: check whether the candidate already exists */
|
||
- candidate = component_find_remote_candidate(component, addr, transport);
|
||
- if (candidate) {
|
||
+ candidate = nice_component_find_remote_candidate (component, addr, transport);
|
||
+
|
||
+ /* If it was a discovered remote peer reflexive candidate, then it should
|
||
+ * be updated according to RFC 5245 section 7.2.1.3 */
|
||
+ if (candidate && candidate->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE &&
|
||
+ candidate->priority == priority) {
|
||
+ nice_debug ("Agent %p : Updating existing peer-rfx remote candidate to %s",
|
||
+ agent, _cand_type_to_sdp (type));
|
||
+ candidate->type = type;
|
||
+ /* If it got there, the next one will also be ran, so the foundation
|
||
+ * will be set.
|
||
+ */
|
||
+ }
|
||
+
|
||
+ if (candidate && candidate->type == type) {
|
||
if (nice_debug_is_enabled ()) {
|
||
gchar tmpbuf[INET6_ADDRSTRLEN];
|
||
nice_address_to_string (addr, tmpbuf);
|
||
@@ -3051,7 +3130,6 @@ static gboolean priv_add_remote_candidate (
|
||
username, password, priority);
|
||
}
|
||
/* case 1: an existing candidate, update the attributes */
|
||
- candidate->type = type;
|
||
if (base_addr)
|
||
candidate->base_addr = *base_addr;
|
||
candidate->priority = priority;
|
||
@@ -3136,7 +3214,7 @@ nice_agent_set_remote_credentials (
|
||
guint stream_id,
|
||
const gchar *ufrag, const gchar *pwd)
|
||
{
|
||
- Stream *stream;
|
||
+ NiceStream *stream;
|
||
gboolean ret = FALSE;
|
||
|
||
g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
|
||
@@ -3167,7 +3245,7 @@ nice_agent_set_local_credentials (
|
||
const gchar *ufrag,
|
||
const gchar *pwd)
|
||
{
|
||
- Stream *stream;
|
||
+ NiceStream *stream;
|
||
gboolean ret = FALSE;
|
||
|
||
g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
|
||
@@ -3198,7 +3276,7 @@ nice_agent_get_local_credentials (
|
||
guint stream_id,
|
||
gchar **ufrag, gchar **pwd)
|
||
{
|
||
- Stream *stream;
|
||
+ NiceStream *stream;
|
||
gboolean ret = TRUE;
|
||
|
||
g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
|
||
@@ -3226,8 +3304,8 @@ nice_agent_get_local_credentials (
|
||
}
|
||
|
||
static int
|
||
-_set_remote_candidates_locked (NiceAgent *agent, Stream *stream,
|
||
- Component *component, const GSList *candidates)
|
||
+_set_remote_candidates_locked (NiceAgent *agent, NiceStream *stream,
|
||
+ NiceComponent *component, const GSList *candidates)
|
||
{
|
||
const GSList *i;
|
||
int added = 0;
|
||
@@ -3253,12 +3331,10 @@ _set_remote_candidates_locked (NiceAgent *agent, Stream *stream,
|
||
}
|
||
}
|
||
|
||
- conn_check_remote_candidates_set(agent);
|
||
+ conn_check_remote_candidates_set(agent, stream, component);
|
||
|
||
if (added > 0) {
|
||
- gboolean res = conn_check_schedule_next (agent);
|
||
- if (res != TRUE)
|
||
- nice_debug ("Agent %p : Warning: unable to schedule any conn checks!", agent);
|
||
+ conn_check_schedule_next (agent);
|
||
}
|
||
|
||
return added;
|
||
@@ -3269,8 +3345,8 @@ NICEAPI_EXPORT int
|
||
nice_agent_set_remote_candidates (NiceAgent *agent, guint stream_id, guint component_id, const GSList *candidates)
|
||
{
|
||
int added = 0;
|
||
- Stream *stream;
|
||
- Component *component;
|
||
+ NiceStream *stream;
|
||
+ NiceComponent *component;
|
||
|
||
g_return_val_if_fail (NICE_IS_AGENT (agent), 0);
|
||
g_return_val_if_fail (stream_id >= 1, 0);
|
||
@@ -3329,14 +3405,15 @@ typedef enum {
|
||
static RecvStatus
|
||
agent_recv_message_unlocked (
|
||
NiceAgent *agent,
|
||
- Stream *stream,
|
||
- Component *component,
|
||
+ NiceStream *stream,
|
||
+ NiceComponent *component,
|
||
NiceSocket *nicesock,
|
||
NiceInputMessage *message)
|
||
{
|
||
NiceAddress from;
|
||
GList *item;
|
||
gint retval;
|
||
+ gboolean is_turn = FALSE;
|
||
|
||
/* We need an address for packet parsing, below. */
|
||
if (message->from == NULL) {
|
||
@@ -3383,7 +3460,7 @@ agent_recv_message_unlocked (
|
||
n_bufs = message->n_buffers;
|
||
}
|
||
|
||
- local_bufs = g_malloc_n (n_bufs + 1, sizeof (GInputVector));
|
||
+ local_bufs = g_alloca ((n_bufs + 1) * sizeof (GInputVector));
|
||
local_message.buffers = local_bufs;
|
||
local_message.n_buffers = n_bufs + 1;
|
||
local_message.from = message->from;
|
||
@@ -3400,7 +3477,6 @@ agent_recv_message_unlocked (
|
||
if (retval == 1) {
|
||
message->length = ntohs (rfc4571_frame);
|
||
}
|
||
- g_free (local_bufs);
|
||
} else {
|
||
if (nicesock->type == NICE_SOCKET_TYPE_TCP_PASSIVE) {
|
||
NiceSocket *new_socket;
|
||
@@ -3411,7 +3487,7 @@ agent_recv_message_unlocked (
|
||
new_socket = nice_tcp_passive_socket_accept (nicesock);
|
||
if (new_socket) {
|
||
_priv_set_socket_tos (agent, new_socket, stream->tos);
|
||
- component_attach_socket (component, new_socket);
|
||
+ nice_component_attach_socket (component, new_socket);
|
||
}
|
||
retval = 0;
|
||
} else {
|
||
@@ -3481,7 +3557,7 @@ agent_recv_message_unlocked (
|
||
n_bufs = message->n_buffers;
|
||
}
|
||
|
||
- local_bufs = g_malloc_n (n_bufs, sizeof (GInputVector));
|
||
+ local_bufs = g_alloca (n_bufs * sizeof (GInputVector));
|
||
local_message.buffers = local_bufs;
|
||
local_message.from = message->from;
|
||
local_message.length = 0;
|
||
@@ -3508,7 +3584,6 @@ agent_recv_message_unlocked (
|
||
message->length = local_message.length;
|
||
agent->rfc4571_expecting_length -= local_message.length;
|
||
}
|
||
- g_free (local_bufs);
|
||
}
|
||
}
|
||
}
|
||
@@ -3516,7 +3591,7 @@ agent_recv_message_unlocked (
|
||
retval = nice_socket_recv_messages (nicesock, message, 1);
|
||
}
|
||
|
||
- nice_debug ("%s: Received %d valid messages of length %" G_GSIZE_FORMAT
|
||
+ nice_debug_verbose ("%s: Received %d valid messages of length %" G_GSIZE_FORMAT
|
||
" from base socket %p.", G_STRFUNC, retval, message->length, nicesock);
|
||
|
||
if (retval == 0) {
|
||
@@ -3535,30 +3610,45 @@ agent_recv_message_unlocked (
|
||
goto done;
|
||
}
|
||
|
||
- if (nice_debug_is_enabled ()) {
|
||
+ if (nice_debug_is_verbose ()) {
|
||
gchar tmpbuf[INET6_ADDRSTRLEN];
|
||
nice_address_to_string (message->from, tmpbuf);
|
||
- nice_debug ("Agent %p : Packet received on local socket %d from [%s]:%u (%" G_GSSIZE_FORMAT " octets).", agent,
|
||
+ nice_debug_verbose ("Agent %p : Packet received on local socket %d from [%s]:%u (%" G_GSSIZE_FORMAT " octets).", agent,
|
||
g_socket_get_fd (nicesock->fileno), tmpbuf,
|
||
nice_address_get_port (message->from), message->length);
|
||
}
|
||
|
||
- for (item = component->turn_servers; item; item = g_list_next (item)) {
|
||
+ if (nicesock->type == NICE_SOCKET_TYPE_UDP_TURN)
|
||
+ is_turn = TRUE;
|
||
+
|
||
+ if (!is_turn && component->turn_candidate &&
|
||
+ nice_socket_is_based_on (component->turn_candidate->sockptr, nicesock) &&
|
||
+ nice_address_equal (message->from,
|
||
+ &component->turn_candidate->turn->server)) {
|
||
+ is_turn = TRUE;
|
||
+ retval = nice_udp_turn_socket_parse_recv_message (
|
||
+ component->turn_candidate->sockptr, &nicesock, message);
|
||
+ }
|
||
+
|
||
+ for (item = component->turn_servers; item && !is_turn;
|
||
+ item = g_list_next (item)) {
|
||
TurnServer *turn = item->data;
|
||
GSList *i = NULL;
|
||
|
||
if (!nice_address_equal (message->from, &turn->server))
|
||
continue;
|
||
|
||
- nice_debug ("Agent %p : Packet received from TURN server candidate.",
|
||
+ nice_debug_verbose ("Agent %p : Packet received from TURN server candidate.",
|
||
agent);
|
||
+ is_turn = TRUE;
|
||
|
||
for (i = component->local_candidates; i; i = i->next) {
|
||
NiceCandidate *cand = i->data;
|
||
|
||
if (cand->type == NICE_CANDIDATE_TYPE_RELAYED &&
|
||
+ cand->turn == turn &&
|
||
cand->stream_id == stream->id &&
|
||
- cand->component_id == component->id) {
|
||
+ nice_socket_is_based_on (cand->sockptr, nicesock)) {
|
||
retval = nice_udp_turn_socket_parse_recv_message (cand->sockptr, &nicesock,
|
||
message);
|
||
break;
|
||
@@ -3567,6 +3657,12 @@ agent_recv_message_unlocked (
|
||
break;
|
||
}
|
||
|
||
+ if (agent->force_relay && !is_turn) {
|
||
+ /* Ignore messages not from TURN if TURN is required */
|
||
+ retval = RECV_WOULD_BLOCK; /* EWOULDBLOCK */
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
if (retval == RECV_OOB)
|
||
goto done;
|
||
|
||
@@ -3638,7 +3734,7 @@ agent_recv_message_unlocked (
|
||
|
||
/* Received data on a reliable connection. */
|
||
|
||
- nice_debug ("%s: notifying pseudo-TCP of packet, length %" G_GSIZE_FORMAT,
|
||
+ nice_debug_verbose ("%s: notifying pseudo-TCP of packet, length %" G_GSIZE_FORMAT,
|
||
G_STRFUNC, message->length);
|
||
pseudo_tcp_socket_notify_message (component->tcp, message);
|
||
|
||
@@ -3672,14 +3768,14 @@ nice_debug_input_message_composition (const NiceInputMessage *messages,
|
||
{
|
||
guint i;
|
||
|
||
- if (!nice_debug_is_enabled ())
|
||
+ if (!nice_debug_is_verbose ())
|
||
return;
|
||
|
||
for (i = 0; i < n_messages; i++) {
|
||
const NiceInputMessage *message = &messages[i];
|
||
guint j;
|
||
|
||
- nice_debug ("Message %p (from: %p, length: %" G_GSIZE_FORMAT ")", message,
|
||
+ nice_debug_verbose ("Message %p (from: %p, length: %" G_GSIZE_FORMAT ")", message,
|
||
message->from, message->length);
|
||
|
||
for (j = 0;
|
||
@@ -3688,7 +3784,7 @@ nice_debug_input_message_composition (const NiceInputMessage *messages,
|
||
j++) {
|
||
GInputVector *buffer = &message->buffers[j];
|
||
|
||
- nice_debug ("\tBuffer %p (length: %" G_GSIZE_FORMAT ")", buffer->buffer,
|
||
+ nice_debug_verbose ("\tBuffer %p (length: %" G_GSIZE_FORMAT ")", buffer->buffer,
|
||
buffer->size);
|
||
}
|
||
}
|
||
@@ -3724,7 +3820,7 @@ compact_message (const NiceOutputMessage *message, gsize buffer_length)
|
||
guint8 *
|
||
compact_input_message (const NiceInputMessage *message, gsize *buffer_length)
|
||
{
|
||
- nice_debug ("%s: **WARNING: SLOW PATH**", G_STRFUNC);
|
||
+ nice_debug_verbose ("%s: **WARNING: SLOW PATH**", G_STRFUNC);
|
||
nice_debug_input_message_composition (message, 1);
|
||
|
||
/* This works as long as NiceInputMessage is a subset of eNiceOutputMessage */
|
||
@@ -3742,7 +3838,7 @@ memcpy_buffer_to_input_message (NiceInputMessage *message,
|
||
{
|
||
guint i;
|
||
|
||
- nice_debug ("%s: **WARNING: SLOW PATH**", G_STRFUNC);
|
||
+ nice_debug_verbose ("%s: **WARNING: SLOW PATH**", G_STRFUNC);
|
||
|
||
message->length = 0;
|
||
|
||
@@ -3912,7 +4008,7 @@ nice_input_message_iter_compare (const NiceInputMessageIter *a,
|
||
*
|
||
* Must be called with the io_mutex held. */
|
||
static gint
|
||
-pending_io_messages_recv_messages (Component *component, gboolean reliable,
|
||
+pending_io_messages_recv_messages (NiceComponent *component, gboolean reliable,
|
||
NiceInputMessage *messages, guint n_messages, NiceInputMessageIter *iter)
|
||
{
|
||
gsize len;
|
||
@@ -3986,8 +4082,8 @@ nice_agent_recv_messages_blocking_or_nonblocking (NiceAgent *agent,
|
||
GCancellable *cancellable, GError **error)
|
||
{
|
||
GMainContext *context;
|
||
- Stream *stream;
|
||
- Component *component;
|
||
+ NiceStream *stream;
|
||
+ NiceComponent *component;
|
||
gint n_valid_messages = -1;
|
||
GSource *cancellable_source = NULL;
|
||
gboolean received_enough = FALSE, error_reported = FALSE;
|
||
@@ -4041,7 +4137,7 @@ nice_agent_recv_messages_blocking_or_nonblocking (NiceAgent *agent,
|
||
goto done;
|
||
}
|
||
|
||
- nice_debug ("%s: %p: (%s):", G_STRFUNC, agent,
|
||
+ nice_debug_verbose ("%s: %p: (%s):", G_STRFUNC, agent,
|
||
blocking ? "blocking" : "non-blocking");
|
||
nice_debug_input_message_composition (messages, n_messages);
|
||
|
||
@@ -4050,8 +4146,8 @@ nice_agent_recv_messages_blocking_or_nonblocking (NiceAgent *agent,
|
||
component->recv_messages == NULL);
|
||
|
||
/* Set the component’s receive buffer. */
|
||
- context = component_dup_io_context (component);
|
||
- component_set_io_callback (component, NULL, NULL, messages, n_messages,
|
||
+ context = nice_component_dup_io_context (component);
|
||
+ nice_component_set_io_callback (component, NULL, NULL, messages, n_messages,
|
||
&child_error);
|
||
|
||
/* Add the cancellable as a source. */
|
||
@@ -4074,7 +4170,7 @@ nice_agent_recv_messages_blocking_or_nonblocking (NiceAgent *agent,
|
||
component->recv_messages, component->n_recv_messages,
|
||
&component->recv_messages_iter);
|
||
|
||
- nice_debug ("%s: %p: Received %d valid messages from pending I/O buffer.",
|
||
+ nice_debug_verbose ("%s: %p: Received %d valid messages from pending I/O buffer.",
|
||
G_STRFUNC, agent,
|
||
nice_input_message_iter_get_n_valid_messages (
|
||
&component->recv_messages_iter));
|
||
@@ -4095,7 +4191,7 @@ nice_agent_recv_messages_blocking_or_nonblocking (NiceAgent *agent,
|
||
&component->recv_messages_iter, &child_error);
|
||
adjust_tcp_clock (agent, stream, component);
|
||
|
||
- nice_debug ("%s: %p: Received %d valid messages from pseudo-TCP read "
|
||
+ nice_debug_verbose ("%s: %p: Received %d valid messages from pseudo-TCP read "
|
||
"buffer.", G_STRFUNC, agent,
|
||
nice_input_message_iter_get_n_valid_messages (
|
||
&component->recv_messages_iter));
|
||
@@ -4125,7 +4221,7 @@ nice_agent_recv_messages_blocking_or_nonblocking (NiceAgent *agent,
|
||
memcpy (&prev_recv_messages_iter, &component->recv_messages_iter,
|
||
sizeof (NiceInputMessageIter));
|
||
|
||
- agent_unlock_and_emit (agent);
|
||
+ agent_unlock ();
|
||
g_main_context_iteration (context, blocking);
|
||
agent_lock ();
|
||
|
||
@@ -4159,7 +4255,7 @@ nice_agent_recv_messages_blocking_or_nonblocking (NiceAgent *agent,
|
||
nice_input_message_iter_get_n_valid_messages (
|
||
&component->recv_messages_iter); /* grab before resetting the iter */
|
||
|
||
- component_set_io_callback (component, NULL, NULL, NULL, 0, NULL);
|
||
+ nice_component_set_io_callback (component, NULL, NULL, NULL, 0, NULL);
|
||
|
||
recv_error:
|
||
/* Tidy up. Below this point, @component may be %NULL. */
|
||
@@ -4179,7 +4275,7 @@ recv_error:
|
||
n_valid_messages = -1;
|
||
}
|
||
|
||
- nice_debug ("%s: %p: n_valid_messages: %d, n_messages: %u", G_STRFUNC, agent,
|
||
+ nice_debug_verbose ("%s: %p: n_valid_messages: %d, n_messages: %u", G_STRFUNC, agent,
|
||
n_valid_messages, n_messages);
|
||
|
||
done:
|
||
@@ -4311,8 +4407,8 @@ nice_agent_send_messages_nonblocking_internal (
|
||
gboolean allow_partial,
|
||
GError **error)
|
||
{
|
||
- Stream *stream;
|
||
- Component *component;
|
||
+ NiceStream *stream;
|
||
+ NiceComponent *component;
|
||
gint n_sent = -1; /* is in bytes if allow_partial is TRUE,
|
||
otherwise in messages */
|
||
GError *child_error = NULL;
|
||
@@ -4335,7 +4431,7 @@ nice_agent_send_messages_nonblocking_internal (
|
||
gchar tmpbuf[INET6_ADDRSTRLEN];
|
||
nice_address_to_string (&component->selected_pair.remote->addr, tmpbuf);
|
||
|
||
- nice_debug ("Agent %p : s%d:%d: sending %u messages to "
|
||
+ nice_debug_verbose ("Agent %p : s%d:%d: sending %u messages to "
|
||
"[%s]:%d", agent, stream_id, component_id, n_messages, tmpbuf,
|
||
nice_address_get_port (&component->selected_pair.remote->addr));
|
||
}
|
||
@@ -4485,7 +4581,7 @@ nice_agent_send_messages_nonblocking_internal (
|
||
n_sent = -1;
|
||
}
|
||
|
||
- nice_debug ("%s: n_sent: %d, n_messages: %u", G_STRFUNC,
|
||
+ nice_debug_verbose ("%s: n_sent: %d, n_messages: %u", G_STRFUNC,
|
||
n_sent, n_messages);
|
||
|
||
done:
|
||
@@ -4558,7 +4654,7 @@ nice_agent_get_local_candidates (
|
||
guint stream_id,
|
||
guint component_id)
|
||
{
|
||
- Component *component;
|
||
+ NiceComponent *component;
|
||
GSList * ret = NULL;
|
||
GSList * item = NULL;
|
||
|
||
@@ -4572,8 +4668,14 @@ nice_agent_get_local_candidates (
|
||
goto done;
|
||
}
|
||
|
||
- for (item = component->local_candidates; item; item = item->next)
|
||
- ret = g_slist_append (ret, nice_candidate_copy (item->data));
|
||
+ for (item = component->local_candidates; item; item = item->next) {
|
||
+ NiceCandidate *cand = item->data;
|
||
+
|
||
+ if (agent->force_relay && cand->type != NICE_CANDIDATE_TYPE_RELAYED)
|
||
+ continue;
|
||
+
|
||
+ ret = g_slist_append (ret, nice_candidate_copy (cand));
|
||
+ }
|
||
|
||
done:
|
||
agent_unlock_and_emit (agent);
|
||
@@ -4587,7 +4689,7 @@ nice_agent_get_remote_candidates (
|
||
guint stream_id,
|
||
guint component_id)
|
||
{
|
||
- Component *component;
|
||
+ NiceComponent *component;
|
||
GSList *ret = NULL, *item = NULL;
|
||
|
||
g_return_val_if_fail (NICE_IS_AGENT (agent), NULL);
|
||
@@ -4620,11 +4722,11 @@ nice_agent_restart (
|
||
priv_generate_tie_breaker (agent);
|
||
|
||
for (i = agent->streams; i; i = i->next) {
|
||
- Stream *stream = i->data;
|
||
+ NiceStream *stream = i->data;
|
||
|
||
/* step: reset local credentials for the stream and
|
||
* clean up the list of remote candidates */
|
||
- stream_restart (agent, stream);
|
||
+ nice_stream_restart (stream, agent);
|
||
}
|
||
|
||
agent_unlock_and_emit (agent);
|
||
@@ -4637,7 +4739,7 @@ nice_agent_restart_stream (
|
||
guint stream_id)
|
||
{
|
||
gboolean res = FALSE;
|
||
- Stream *stream;
|
||
+ NiceStream *stream;
|
||
|
||
agent_lock();
|
||
|
||
@@ -4649,7 +4751,7 @@ nice_agent_restart_stream (
|
||
|
||
/* step: reset local credentials for the stream and
|
||
* clean up the list of remote candidates */
|
||
- stream_restart (agent, stream);
|
||
+ nice_stream_restart (stream, agent);
|
||
|
||
res = TRUE;
|
||
done:
|
||
@@ -4688,10 +4790,10 @@ nice_agent_dispose (GObject *object)
|
||
|
||
for (i = agent->streams; i; i = i->next)
|
||
{
|
||
- Stream *s = i->data;
|
||
+ NiceStream *s = i->data;
|
||
|
||
- stream_close (s);
|
||
- stream_free (s);
|
||
+ nice_stream_close (s);
|
||
+ g_object_unref (s);
|
||
}
|
||
|
||
g_slist_free (agent->streams);
|
||
@@ -4739,9 +4841,9 @@ gboolean
|
||
component_io_cb (GSocket *gsocket, GIOCondition condition, gpointer user_data)
|
||
{
|
||
SocketSource *socket_source = user_data;
|
||
- Component *component;
|
||
+ NiceComponent *component;
|
||
NiceAgent *agent;
|
||
- Stream *stream;
|
||
+ NiceStream *stream;
|
||
gboolean has_io_callback;
|
||
gboolean remove_source = FALSE;
|
||
|
||
@@ -4774,20 +4876,22 @@ component_io_cb (GSocket *gsocket, GIOCondition condition, gpointer user_data)
|
||
stream->id, component->id, NICE_COMPONENT_STATE_FAILED);
|
||
}
|
||
|
||
- component_detach_socket (component, socket_source->socket);
|
||
+ nice_component_remove_socket (component, socket_source->socket);
|
||
agent_unlock ();
|
||
+ g_object_unref (agent);
|
||
return G_SOURCE_REMOVE;
|
||
}
|
||
|
||
- has_io_callback = component_has_io_callback (component);
|
||
+ has_io_callback = nice_component_has_io_callback (component);
|
||
|
||
/* Choose which receive buffer to use. If we’re reading for
|
||
* nice_agent_attach_recv(), use a local static buffer. If we’re reading for
|
||
* nice_agent_recv_messages(), use the buffer provided by the client.
|
||
*
|
||
* has_io_callback cannot change throughout this function, as we operate
|
||
- * entirely with the agent lock held, and component_set_io_callback() would
|
||
- * need to take the agent lock to change the Component’s io_callback. */
|
||
+ * entirely with the agent lock held, and nice_component_set_io_callback()
|
||
+ * would need to take the agent lock to change the Component’s
|
||
+ * io_callback. */
|
||
g_assert (!has_io_callback || component->recv_messages == NULL);
|
||
|
||
if (agent->reliable && !nice_socket_is_reliable (socket_source->socket)) {
|
||
@@ -4835,7 +4939,7 @@ component_io_cb (GSocket *gsocket, GIOCondition condition, gpointer user_data)
|
||
retval = agent_recv_message_unlocked (agent, stream, component,
|
||
socket_source->socket, &local_message);
|
||
|
||
- nice_debug ("%s: %p: received %d valid messages with %" G_GSSIZE_FORMAT
|
||
+ nice_debug_verbose ("%s: %p: received %d valid messages with %" G_GSSIZE_FORMAT
|
||
" bytes", G_STRFUNC, agent, retval, local_message.length);
|
||
|
||
/* Don’t expect any valid messages to escape pseudo_tcp_socket_readable()
|
||
@@ -4852,7 +4956,7 @@ component_io_cb (GSocket *gsocket, GIOCondition condition, gpointer user_data)
|
||
break;
|
||
}
|
||
|
||
- has_io_callback = component_has_io_callback (component);
|
||
+ has_io_callback = nice_component_has_io_callback (component);
|
||
}
|
||
} else if (has_io_callback) {
|
||
while (has_io_callback) {
|
||
@@ -4865,7 +4969,7 @@ component_io_cb (GSocket *gsocket, GIOCondition condition, gpointer user_data)
|
||
retval = agent_recv_message_unlocked (agent, stream, component,
|
||
socket_source->socket, &local_message);
|
||
|
||
- nice_debug ("%s: %p: received %d valid messages with %" G_GSSIZE_FORMAT
|
||
+ nice_debug_verbose ("%s: %p: received %d valid messages with %" G_GSSIZE_FORMAT
|
||
" bytes", G_STRFUNC, agent, retval, local_message.length);
|
||
|
||
if (retval == RECV_WOULD_BLOCK) {
|
||
@@ -4879,13 +4983,13 @@ component_io_cb (GSocket *gsocket, GIOCondition condition, gpointer user_data)
|
||
}
|
||
|
||
if (retval == RECV_SUCCESS && local_message.length > 0)
|
||
- component_emit_io_callback (component, local_buf, local_message.length);
|
||
+ nice_component_emit_io_callback (component, local_buf, local_message.length);
|
||
|
||
if (g_source_is_destroyed (g_main_current_source ())) {
|
||
nice_debug ("Component IO source disappeared during the callback");
|
||
goto out;
|
||
}
|
||
- has_io_callback = component_has_io_callback (component);
|
||
+ has_io_callback = nice_component_has_io_callback (component);
|
||
}
|
||
} else if (component->recv_messages != NULL) {
|
||
RecvStatus retval;
|
||
@@ -4906,7 +5010,7 @@ component_io_cb (GSocket *gsocket, GIOCondition condition, gpointer user_data)
|
||
socket_source->socket,
|
||
&component->recv_messages[component->recv_messages_iter.message]);
|
||
|
||
- nice_debug ("%s: %p: received %d valid messages", G_STRFUNC, agent,
|
||
+ nice_debug_verbose ("%s: %p: received %d valid messages", G_STRFUNC, agent,
|
||
retval);
|
||
|
||
if (retval == RECV_SUCCESS) {
|
||
@@ -4931,6 +5035,10 @@ component_io_cb (GSocket *gsocket, GIOCondition condition, gpointer user_data)
|
||
}
|
||
|
||
done:
|
||
+
|
||
+ if (remove_source)
|
||
+ nice_component_remove_socket (component, socket_source->socket);
|
||
+
|
||
/* If we’re in the middle of a read, don’t emit any signals, or we could cause
|
||
* re-entrancy by (e.g.) emitting component-state-changed and having the
|
||
* client perform a read. */
|
||
@@ -4946,6 +5054,7 @@ done:
|
||
|
||
out:
|
||
g_object_unref (agent);
|
||
+
|
||
agent_unlock_and_emit (agent);
|
||
return G_SOURCE_REMOVE;
|
||
}
|
||
@@ -4959,8 +5068,8 @@ nice_agent_attach_recv (
|
||
NiceAgentRecvFunc func,
|
||
gpointer data)
|
||
{
|
||
- Component *component = NULL;
|
||
- Stream *stream = NULL;
|
||
+ NiceComponent *component = NULL;
|
||
+ NiceStream *stream = NULL;
|
||
gboolean ret = FALSE;
|
||
|
||
g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
|
||
@@ -4982,8 +5091,8 @@ nice_agent_attach_recv (
|
||
ctx = g_main_context_default ();
|
||
|
||
/* Set the component’s I/O context. */
|
||
- component_set_io_context (component, ctx);
|
||
- component_set_io_callback (component, func, data, NULL, 0, NULL);
|
||
+ nice_component_set_io_context (component, ctx);
|
||
+ nice_component_set_io_callback (component, func, data, NULL, 0, NULL);
|
||
ret = TRUE;
|
||
|
||
if (func) {
|
||
@@ -5011,8 +5120,8 @@ nice_agent_set_selected_pair (
|
||
const gchar *lfoundation,
|
||
const gchar *rfoundation)
|
||
{
|
||
- Component *component;
|
||
- Stream *stream;
|
||
+ NiceComponent *component;
|
||
+ NiceStream *stream;
|
||
CandidatePair pair;
|
||
gboolean ret = FALSE;
|
||
|
||
@@ -5029,7 +5138,7 @@ nice_agent_set_selected_pair (
|
||
goto done;
|
||
}
|
||
|
||
- if (!component_find_pair (component, agent, lfoundation, rfoundation, &pair)){
|
||
+ if (!nice_component_find_pair (component, agent, lfoundation, rfoundation, &pair)){
|
||
goto done;
|
||
}
|
||
|
||
@@ -5044,11 +5153,22 @@ nice_agent_set_selected_pair (
|
||
goto done;
|
||
}
|
||
|
||
- /* step: change component state */
|
||
- agent_signal_component_state_change (agent, stream_id, component_id, NICE_COMPONENT_STATE_READY);
|
||
+ /* step: change component state; we could be in STATE_DISCONNECTED; skip
|
||
+ * STATE_GATHERING and continue through the states to give client code a nice
|
||
+ * logical progression. See http://phabricator.freedesktop.org/D218 for
|
||
+ * discussion. */
|
||
+ if (component->state < NICE_COMPONENT_STATE_CONNECTING ||
|
||
+ component->state == NICE_COMPONENT_STATE_FAILED)
|
||
+ agent_signal_component_state_change (agent, stream_id, component_id,
|
||
+ NICE_COMPONENT_STATE_CONNECTING);
|
||
+ if (component->state < NICE_COMPONENT_STATE_CONNECTED)
|
||
+ agent_signal_component_state_change (agent, stream_id, component_id,
|
||
+ NICE_COMPONENT_STATE_CONNECTED);
|
||
+ agent_signal_component_state_change (agent, stream_id, component_id,
|
||
+ NICE_COMPONENT_STATE_READY);
|
||
|
||
/* step: set the selected pair */
|
||
- component_update_selected_pair (component, &pair);
|
||
+ nice_component_update_selected_pair (component, &pair);
|
||
agent_signal_new_selected_pair (agent, stream_id, component_id,
|
||
pair.local, pair.remote);
|
||
|
||
@@ -5063,8 +5183,8 @@ NICEAPI_EXPORT gboolean
|
||
nice_agent_get_selected_pair (NiceAgent *agent, guint stream_id,
|
||
guint component_id, NiceCandidate **local, NiceCandidate **remote)
|
||
{
|
||
- Component *component;
|
||
- Stream *stream;
|
||
+ NiceComponent *component;
|
||
+ NiceStream *stream;
|
||
gboolean ret = FALSE;
|
||
|
||
g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
|
||
@@ -5096,8 +5216,8 @@ NICEAPI_EXPORT GSocket *
|
||
nice_agent_get_selected_socket (NiceAgent *agent, guint stream_id,
|
||
guint component_id)
|
||
{
|
||
- Component *component;
|
||
- Stream *stream;
|
||
+ NiceComponent *component;
|
||
+ NiceStream *stream;
|
||
NiceSocket *nice_socket;
|
||
GSocket *g_socket = NULL;
|
||
|
||
@@ -5176,8 +5296,8 @@ nice_agent_set_selected_remote_candidate (
|
||
guint component_id,
|
||
NiceCandidate *candidate)
|
||
{
|
||
- Component *component;
|
||
- Stream *stream;
|
||
+ NiceComponent *component;
|
||
+ NiceStream *stream;
|
||
NiceCandidate *lcandidate = NULL;
|
||
gboolean ret = FALSE;
|
||
NiceCandidate *local = NULL, *remote = NULL;
|
||
@@ -5204,7 +5324,7 @@ nice_agent_set_selected_remote_candidate (
|
||
priority = component->selected_pair.priority;
|
||
|
||
/* step: set the selected pair */
|
||
- lcandidate = component_set_selected_remote_candidate (agent, component,
|
||
+ lcandidate = nice_component_set_selected_remote_candidate (component, agent,
|
||
candidate);
|
||
if (!lcandidate)
|
||
goto done;
|
||
@@ -5222,8 +5342,19 @@ nice_agent_set_selected_remote_candidate (
|
||
goto done;
|
||
}
|
||
|
||
- /* step: change component state */
|
||
- agent_signal_component_state_change (agent, stream_id, component_id, NICE_COMPONENT_STATE_READY);
|
||
+ /* step: change component state; we could be in STATE_DISCONNECTED; skip
|
||
+ * STATE_GATHERING and continue through the states to give client code a nice
|
||
+ * logical progression. See http://phabricator.freedesktop.org/D218 for
|
||
+ * discussion. */
|
||
+ if (component->state < NICE_COMPONENT_STATE_CONNECTING ||
|
||
+ component->state == NICE_COMPONENT_STATE_FAILED)
|
||
+ agent_signal_component_state_change (agent, stream_id, component_id,
|
||
+ NICE_COMPONENT_STATE_CONNECTING);
|
||
+ if (component->state < NICE_COMPONENT_STATE_CONNECTED)
|
||
+ agent_signal_component_state_change (agent, stream_id, component_id,
|
||
+ NICE_COMPONENT_STATE_CONNECTED);
|
||
+ agent_signal_component_state_change (agent, stream_id, component_id,
|
||
+ NICE_COMPONENT_STATE_READY);
|
||
|
||
agent_signal_new_selected_pair (agent, stream_id, component_id,
|
||
lcandidate, candidate);
|
||
@@ -5261,7 +5392,7 @@ nice_agent_set_stream_tos (NiceAgent *agent,
|
||
guint stream_id, gint tos)
|
||
{
|
||
GSList *i, *j;
|
||
- Stream *stream;
|
||
+ NiceStream *stream;
|
||
|
||
g_return_if_fail (NICE_IS_AGENT (agent));
|
||
g_return_if_fail (stream_id >= 1);
|
||
@@ -5274,7 +5405,7 @@ nice_agent_set_stream_tos (NiceAgent *agent,
|
||
|
||
stream->tos = tos;
|
||
for (i = stream->components; i; i = i->next) {
|
||
- Component *component = i->data;
|
||
+ NiceComponent *component = i->data;
|
||
|
||
for (j = component->local_candidates; j; j = j->next) {
|
||
NiceCandidate *local_candidate = j->data;
|
||
@@ -5308,7 +5439,7 @@ NICEAPI_EXPORT gboolean
|
||
nice_agent_set_stream_name (NiceAgent *agent, guint stream_id,
|
||
const gchar *name)
|
||
{
|
||
- Stream *stream_to_name = NULL;
|
||
+ NiceStream *stream_to_name = NULL;
|
||
GSList *i;
|
||
gboolean ret = FALSE;
|
||
|
||
@@ -5329,16 +5460,14 @@ nice_agent_set_stream_name (NiceAgent *agent, guint stream_id,
|
||
|
||
agent_lock();
|
||
|
||
- if (name != NULL) {
|
||
- for (i = agent->streams; i; i = i->next) {
|
||
- Stream *stream = i->data;
|
||
+ for (i = agent->streams; i; i = i->next) {
|
||
+ NiceStream *stream = i->data;
|
||
|
||
- if (stream->id != stream_id &&
|
||
- g_strcmp0 (stream->name, name) == 0)
|
||
- goto done;
|
||
- else if (stream->id == stream_id)
|
||
- stream_to_name = stream;
|
||
- }
|
||
+ if (stream->id != stream_id &&
|
||
+ g_strcmp0 (stream->name, name) == 0)
|
||
+ goto done;
|
||
+ else if (stream->id == stream_id)
|
||
+ stream_to_name = stream;
|
||
}
|
||
|
||
if (stream_to_name == NULL)
|
||
@@ -5358,7 +5487,7 @@ nice_agent_set_stream_name (NiceAgent *agent, guint stream_id,
|
||
NICEAPI_EXPORT const gchar *
|
||
nice_agent_get_stream_name (NiceAgent *agent, guint stream_id)
|
||
{
|
||
- Stream *stream;
|
||
+ NiceStream *stream;
|
||
gchar *name = NULL;
|
||
|
||
g_return_val_if_fail (NICE_IS_AGENT (agent), NULL);
|
||
@@ -5379,14 +5508,14 @@ nice_agent_get_stream_name (NiceAgent *agent, guint stream_id)
|
||
|
||
static NiceCandidate *
|
||
_get_default_local_candidate_locked (NiceAgent *agent,
|
||
- Stream *stream, Component *component)
|
||
+ NiceStream *stream, NiceComponent *component)
|
||
{
|
||
GSList *i;
|
||
NiceCandidate *default_candidate = NULL;
|
||
NiceCandidate *default_rtp_candidate = NULL;
|
||
|
||
if (component->id != NICE_COMPONENT_TYPE_RTP) {
|
||
- Component *rtp_component;
|
||
+ NiceComponent *rtp_component;
|
||
|
||
if (!agent_find_component (agent, stream->id, NICE_COMPONENT_TYPE_RTP,
|
||
NULL, &rtp_component))
|
||
@@ -5402,6 +5531,10 @@ _get_default_local_candidate_locked (NiceAgent *agent,
|
||
for (i = component->local_candidates; i; i = i->next) {
|
||
NiceCandidate *local_candidate = i->data;
|
||
|
||
+ if (agent->force_relay &&
|
||
+ local_candidate->type != NICE_CANDIDATE_TYPE_RELAYED)
|
||
+ continue;
|
||
+
|
||
/* Only check for ipv4 candidates */
|
||
if (nice_address_ip_version (&local_candidate->addr) != 4)
|
||
continue;
|
||
@@ -5426,8 +5559,8 @@ NICEAPI_EXPORT NiceCandidate *
|
||
nice_agent_get_default_local_candidate (NiceAgent *agent,
|
||
guint stream_id, guint component_id)
|
||
{
|
||
- Stream *stream = NULL;
|
||
- Component *component = NULL;
|
||
+ NiceStream *stream = NULL;
|
||
+ NiceComponent *component = NULL;
|
||
NiceCandidate *default_candidate = NULL;
|
||
|
||
g_return_val_if_fail (NICE_IS_AGENT (agent), NULL);
|
||
@@ -5526,7 +5659,7 @@ _generate_candidate_sdp (NiceAgent *agent,
|
||
}
|
||
|
||
static void
|
||
-_generate_stream_sdp (NiceAgent *agent, Stream *stream,
|
||
+_generate_stream_sdp (NiceAgent *agent, NiceStream *stream,
|
||
GString *sdp, gboolean include_non_ice)
|
||
{
|
||
GSList *i, *j;
|
||
@@ -5542,7 +5675,7 @@ _generate_stream_sdp (NiceAgent *agent, Stream *stream,
|
||
|
||
/* Find default candidates */
|
||
for (i = stream->components; i; i = i->next) {
|
||
- Component *component = i->data;
|
||
+ NiceComponent *component = i->data;
|
||
NiceCandidate *default_candidate;
|
||
|
||
if (component->id == NICE_COMPONENT_TYPE_RTP) {
|
||
@@ -5571,11 +5704,14 @@ _generate_stream_sdp (NiceAgent *agent, Stream *stream,
|
||
g_string_append_printf (sdp, "a=ice-pwd:%s\n", stream->local_password);
|
||
|
||
for (i = stream->components; i; i = i->next) {
|
||
- Component *component = i->data;
|
||
+ NiceComponent *component = i->data;
|
||
|
||
for (j = component->local_candidates; j; j = j->next) {
|
||
NiceCandidate *candidate = j->data;
|
||
|
||
+ if (agent->force_relay && candidate->type != NICE_CANDIDATE_TYPE_RELAYED)
|
||
+ continue;
|
||
+
|
||
_generate_candidate_sdp (agent, candidate, sdp);
|
||
g_string_append (sdp, "\n");
|
||
}
|
||
@@ -5593,7 +5729,7 @@ nice_agent_generate_local_sdp (NiceAgent *agent)
|
||
agent_lock();
|
||
|
||
for (i = agent->streams; i; i = i->next) {
|
||
- Stream *stream = i->data;
|
||
+ NiceStream *stream = i->data;
|
||
|
||
_generate_stream_sdp (agent, stream, sdp, TRUE);
|
||
}
|
||
@@ -5609,7 +5745,7 @@ nice_agent_generate_local_stream_sdp (NiceAgent *agent, guint stream_id,
|
||
{
|
||
GString *sdp = NULL;
|
||
gchar *ret = NULL;
|
||
- Stream *stream;
|
||
+ NiceStream *stream;
|
||
|
||
g_return_val_if_fail (NICE_IS_AGENT (agent), NULL);
|
||
g_return_val_if_fail (stream_id >= 1, NULL);
|
||
@@ -5652,7 +5788,7 @@ nice_agent_generate_local_candidate_sdp (NiceAgent *agent,
|
||
NICEAPI_EXPORT gint
|
||
nice_agent_parse_remote_sdp (NiceAgent *agent, const gchar *sdp)
|
||
{
|
||
- Stream *current_stream = NULL;
|
||
+ NiceStream *current_stream = NULL;
|
||
gchar **sdp_lines = NULL;
|
||
GSList *l, *stream_item = NULL;
|
||
gint i;
|
||
@@ -5664,7 +5800,7 @@ nice_agent_parse_remote_sdp (NiceAgent *agent, const gchar *sdp)
|
||
agent_lock();
|
||
|
||
for (l = agent->streams; l; l = l->next) {
|
||
- Stream *stream = l->data;
|
||
+ NiceStream *stream = l->data;
|
||
|
||
if (stream->name == NULL) {
|
||
ret = -1;
|
||
@@ -5701,7 +5837,7 @@ nice_agent_parse_remote_sdp (NiceAgent *agent, const gchar *sdp)
|
||
NICE_STREAM_MAX_PWD);
|
||
} else if (g_str_has_prefix (sdp_lines[i], "a=candidate:")) {
|
||
NiceCandidate *candidate = NULL;
|
||
- Component *component = NULL;
|
||
+ NiceComponent *component = NULL;
|
||
GSList *cands = NULL;
|
||
gint added;
|
||
|
||
@@ -5744,7 +5880,7 @@ NICEAPI_EXPORT GSList *
|
||
nice_agent_parse_remote_stream_sdp (NiceAgent *agent, guint stream_id,
|
||
const gchar *sdp, gchar **ufrag, gchar **pwd)
|
||
{
|
||
- Stream *stream = NULL;
|
||
+ NiceStream *stream = NULL;
|
||
gchar **sdp_lines = NULL;
|
||
GSList *candidates = NULL;
|
||
gint i;
|
||
@@ -5924,7 +6060,7 @@ nice_agent_get_io_stream (NiceAgent *agent, guint stream_id,
|
||
guint component_id)
|
||
{
|
||
GIOStream *iostream = NULL;
|
||
- Component *component;
|
||
+ NiceComponent *component;
|
||
|
||
g_return_val_if_fail (NICE_IS_AGENT (agent), NULL);
|
||
g_return_val_if_fail (stream_id >= 1, NULL);
|
||
@@ -5951,7 +6087,7 @@ nice_agent_get_io_stream (NiceAgent *agent, guint stream_id,
|
||
NICEAPI_EXPORT gboolean
|
||
nice_agent_forget_relays (NiceAgent *agent, guint stream_id, guint component_id)
|
||
{
|
||
- Component *component;
|
||
+ NiceComponent *component;
|
||
gboolean ret = TRUE;
|
||
|
||
g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
|
||
@@ -5965,7 +6101,7 @@ nice_agent_forget_relays (NiceAgent *agent, guint stream_id, guint component_id)
|
||
goto done;
|
||
}
|
||
|
||
- component_clean_turn_servers (component);
|
||
+ nice_component_clean_turn_servers (component);
|
||
|
||
done:
|
||
agent_unlock_and_emit (agent);
|
||
@@ -6013,7 +6149,7 @@ nice_agent_get_component_state (NiceAgent *agent,
|
||
guint stream_id, guint component_id)
|
||
{
|
||
NiceComponentState state = NICE_COMPONENT_STATE_FAILED;
|
||
- Component *component;
|
||
+ NiceComponent *component;
|
||
|
||
agent_lock ();
|
||
|
||
diff --git a/agent/candidate.c b/agent/candidate.c
|
||
index a472c4a..68c7714 100644
|
||
--- a/agent/candidate.c
|
||
+++ b/agent/candidate.c
|
||
@@ -52,6 +52,7 @@
|
||
|
||
#include "agent.h"
|
||
#include "component.h"
|
||
+#include "interfaces.h"
|
||
|
||
G_DEFINE_BOXED_TYPE (NiceCandidate, nice_candidate, nice_candidate_copy,
|
||
nice_candidate_free);
|
||
@@ -144,6 +145,43 @@ nice_candidate_ice_local_preference_full (guint direction_preference,
|
||
other_preference);
|
||
}
|
||
|
||
+static guint8
|
||
+nice_candidate_ip_local_preference (const NiceCandidate *candidate)
|
||
+{
|
||
+ guint8 preference = 0;
|
||
+ gchar ip_string[INET6_ADDRSTRLEN];
|
||
+ GList/*<owned gchar*>*/ *ips = NULL;
|
||
+ GList/*<unowned gchar*>*/ *iter;
|
||
+
|
||
+ /* Ensure otherwise identical host candidates with only different IP addresses
|
||
+ * (multihomed host) get assigned different priorities. Position of the IP in
|
||
+ * the list obtained from nice_interfaces_get_local_ips() serves here as the
|
||
+ * distinguishing value of other_preference. Reflexive and relayed candidates
|
||
+ * are likewise differentiated by their base address.
|
||
+ *
|
||
+ * This is required by RFC 5245 Section 4.1.2.1:
|
||
+ * https://tools.ietf.org/html/rfc5245#section-4.1.2.1
|
||
+ */
|
||
+ if (candidate->type == NICE_CANDIDATE_TYPE_HOST) {
|
||
+ nice_address_to_string (&candidate->addr, ip_string);
|
||
+ } else {
|
||
+ nice_address_to_string (&candidate->base_addr, ip_string);
|
||
+ }
|
||
+
|
||
+ ips = nice_interfaces_get_local_ips (TRUE);
|
||
+
|
||
+ for (iter = ips; iter; iter = g_list_next (iter)) {
|
||
+ if (g_strcmp0 (ip_string, iter->data) == 0) {
|
||
+ break;
|
||
+ }
|
||
+ ++preference;
|
||
+ }
|
||
+
|
||
+ g_list_free_full (ips, g_free);
|
||
+
|
||
+ return preference;
|
||
+}
|
||
+
|
||
static guint16
|
||
nice_candidate_ice_local_preference (const NiceCandidate *candidate)
|
||
{
|
||
@@ -178,7 +216,8 @@ nice_candidate_ice_local_preference (const NiceCandidate *candidate)
|
||
break;
|
||
}
|
||
|
||
- return nice_candidate_ice_local_preference_full (direction_preference, 1);
|
||
+ return nice_candidate_ice_local_preference_full (direction_preference,
|
||
+ nice_candidate_ip_local_preference (candidate));
|
||
}
|
||
|
||
static guint32
|
||
@@ -214,7 +253,7 @@ nice_candidate_ms_ice_local_preference (const NiceCandidate *candidate)
|
||
}
|
||
|
||
return nice_candidate_ms_ice_local_preference_full(transport_preference,
|
||
- direction_preference, 0);
|
||
+ direction_preference, nice_candidate_ip_local_preference (candidate));
|
||
}
|
||
|
||
static guint8
|
||
@@ -238,7 +277,10 @@ nice_candidate_ice_type_preference (const NiceCandidate *candidate,
|
||
type_preference = NICE_CANDIDATE_TYPE_PREF_SERVER_REFLEXIVE;
|
||
break;
|
||
case NICE_CANDIDATE_TYPE_RELAYED:
|
||
- type_preference = NICE_CANDIDATE_TYPE_PREF_RELAYED;
|
||
+ if (candidate->turn->type == NICE_RELAY_TYPE_TURN_UDP)
|
||
+ type_preference = NICE_CANDIDATE_TYPE_PREF_RELAYED_UDP;
|
||
+ else
|
||
+ type_preference = NICE_CANDIDATE_TYPE_PREF_RELAYED;
|
||
break;
|
||
default:
|
||
type_preference = 0;
|
||
diff --git a/agent/candidate.h b/agent/candidate.h
|
||
index 5e0eaf3..fadfce3 100644
|
||
--- a/agent/candidate.h
|
||
+++ b/agent/candidate.h
|
||
@@ -64,8 +64,8 @@ G_BEGIN_DECLS
|
||
#define NICE_CANDIDATE_TYPE_PREF_PEER_REFLEXIVE 110
|
||
#define NICE_CANDIDATE_TYPE_PREF_NAT_ASSISTED 105
|
||
#define NICE_CANDIDATE_TYPE_PREF_SERVER_REFLEXIVE 100
|
||
-#define NICE_CANDIDATE_TYPE_PREF_UDP_TUNNELED 75
|
||
-#define NICE_CANDIDATE_TYPE_PREF_RELAYED 10
|
||
+#define NICE_CANDIDATE_TYPE_PREF_RELAYED_UDP 30
|
||
+#define NICE_CANDIDATE_TYPE_PREF_RELAYED 20
|
||
|
||
/* Priority preference constants for MS-ICE compatibility */
|
||
#define NICE_CANDIDATE_TRANSPORT_MS_PREF_UDP 15
|
||
diff --git a/agent/component.c b/agent/component.c
|
||
index 1a1f84a..d38d3e5 100644
|
||
--- a/agent/component.c
|
||
+++ b/agent/component.c
|
||
@@ -59,11 +59,33 @@ static volatile unsigned int n_components_destroyed = 0;
|
||
#include "discovery.h"
|
||
#include "agent-priv.h"
|
||
|
||
+G_DEFINE_TYPE (NiceComponent, nice_component, G_TYPE_OBJECT);
|
||
|
||
+typedef enum {
|
||
+ PROP_ID = 1,
|
||
+ PROP_AGENT,
|
||
+ PROP_STREAM,
|
||
+} NiceComponentProperty;
|
||
+
|
||
+static void
|
||
+nice_component_constructed (GObject *obj);
|
||
static void
|
||
-component_schedule_io_callback (Component *component);
|
||
+nice_component_get_property (GObject *obj,
|
||
+ guint property_id, GValue *value, GParamSpec *pspec);
|
||
static void
|
||
-component_deschedule_io_callback (Component *component);
|
||
+nice_component_set_property (GObject *obj,
|
||
+ guint property_id, const GValue *value, GParamSpec *pspec);
|
||
+static void
|
||
+nice_component_finalize (GObject *obj);
|
||
+
|
||
+static void
|
||
+nice_component_schedule_io_callback (NiceComponent *component);
|
||
+static void
|
||
+nice_component_deschedule_io_callback (NiceComponent *component);
|
||
+static void
|
||
+nice_component_detach_socket (NiceComponent *component, NiceSocket *nicesock);
|
||
+static void
|
||
+nice_component_clear_selected_pair (NiceComponent *component);
|
||
|
||
|
||
void
|
||
@@ -74,12 +96,15 @@ incoming_check_free (IncomingCheck *icheck)
|
||
}
|
||
|
||
/* Must *not* take the agent lock, since it’s called from within
|
||
- * component_set_io_context(), which holds the Component’s I/O lock. */
|
||
+ * nice_component_set_io_context(), which holds the Component’s I/O lock. */
|
||
static void
|
||
socket_source_attach (SocketSource *socket_source, GMainContext *context)
|
||
{
|
||
GSource *source;
|
||
|
||
+ if (socket_source->socket->fileno == NULL)
|
||
+ return;
|
||
+
|
||
/* Create a source. */
|
||
source = g_socket_create_source (socket_source->socket->fileno,
|
||
G_IO_IN, NULL);
|
||
@@ -121,50 +146,57 @@ socket_source_free (SocketSource *source)
|
||
g_slice_free (SocketSource, source);
|
||
}
|
||
|
||
-Component *
|
||
-component_new (guint id, NiceAgent *agent, Stream *stream)
|
||
+NiceComponent *
|
||
+nice_component_new (guint id, NiceAgent *agent, NiceStream *stream)
|
||
{
|
||
- Component *component;
|
||
-
|
||
- g_atomic_int_inc (&n_components_created);
|
||
- nice_debug ("Created NiceComponent (%u created, %u destroyed)",
|
||
- n_components_created, n_components_destroyed);
|
||
+ return g_object_new (NICE_TYPE_COMPONENT,
|
||
+ "id", id,
|
||
+ "agent", agent,
|
||
+ "stream", stream,
|
||
+ NULL);
|
||
+}
|
||
|
||
- component = g_slice_new0 (Component);
|
||
- component->id = id;
|
||
- component->state = NICE_COMPONENT_STATE_DISCONNECTED;
|
||
- component->restart_candidate = NULL;
|
||
- component->tcp = NULL;
|
||
- component->agent = agent;
|
||
- component->stream = stream;
|
||
+void
|
||
+nice_component_remove_socket (NiceComponent *cmp, NiceSocket *nsocket)
|
||
+{
|
||
+ GSList *i;
|
||
|
||
- nice_agent_init_stun_agent (agent, &component->stun_agent);
|
||
+ for (i = cmp->local_candidates; i;) {
|
||
+ NiceCandidate *candidate = i->data;
|
||
+ GSList *next = i->next;
|
||
|
||
- g_mutex_init (&component->io_mutex);
|
||
- g_queue_init (&component->pending_io_messages);
|
||
- component->io_callback_id = 0;
|
||
+ if (!nice_socket_is_based_on (candidate->sockptr, nsocket)) {
|
||
+ i = next;
|
||
+ continue;
|
||
+ }
|
||
|
||
- component->own_ctx = g_main_context_new ();
|
||
- component->stop_cancellable = g_cancellable_new ();
|
||
- component->stop_cancellable_source =
|
||
- g_cancellable_source_new (component->stop_cancellable);
|
||
- g_source_set_dummy_callback (component->stop_cancellable_source);
|
||
- g_source_attach (component->stop_cancellable_source, component->own_ctx);
|
||
- component->ctx = g_main_context_ref (component->own_ctx);
|
||
+ if (candidate == cmp->selected_pair.local) {
|
||
+ nice_component_clear_selected_pair (cmp);
|
||
+ agent_signal_component_state_change (cmp->agent, cmp->stream->id,
|
||
+ cmp->id, NICE_COMPONENT_STATE_FAILED);
|
||
+ }
|
||
|
||
- /* Start off with a fresh main context and all I/O paused. This
|
||
- * will be updated when nice_agent_attach_recv() or nice_agent_recv_messages()
|
||
- * are called. */
|
||
- component_set_io_context (component, NULL);
|
||
- component_set_io_callback (component, NULL, NULL, NULL, 0, NULL);
|
||
+ refresh_prune_candidate (cmp->agent, candidate);
|
||
+ if (candidate->sockptr != nsocket) {
|
||
+ discovery_prune_socket (cmp->agent, candidate->sockptr);
|
||
+ conn_check_prune_socket (cmp->agent, cmp->stream, cmp,
|
||
+ candidate->sockptr);
|
||
+ nice_component_detach_socket (cmp, candidate->sockptr);
|
||
+ }
|
||
+ agent_remove_local_candidate (cmp->agent, candidate);
|
||
+ nice_candidate_free (candidate);
|
||
|
||
- g_queue_init (&component->queued_tcp_packets);
|
||
+ cmp->local_candidates = g_slist_delete_link (cmp->local_candidates, i);
|
||
+ i = next;
|
||
+ }
|
||
|
||
- return component;
|
||
+ discovery_prune_socket (cmp->agent, nsocket);
|
||
+ conn_check_prune_socket (cmp->agent, cmp->stream, cmp, nsocket);
|
||
+ nice_component_detach_socket (cmp, nsocket);
|
||
}
|
||
|
||
void
|
||
-component_clean_turn_servers (Component *cmp)
|
||
+nice_component_clean_turn_servers (NiceComponent *cmp)
|
||
{
|
||
GSList *i;
|
||
|
||
@@ -195,7 +227,7 @@ component_clean_turn_servers (Component *cmp)
|
||
discovery_prune_socket (cmp->agent, cmp->turn_candidate->sockptr);
|
||
conn_check_prune_socket (cmp->agent, cmp->stream, cmp,
|
||
cmp->turn_candidate->sockptr);
|
||
- component_detach_socket (cmp, cmp->turn_candidate->sockptr);
|
||
+ nice_component_detach_socket (cmp, cmp->turn_candidate->sockptr);
|
||
nice_candidate_free (cmp->turn_candidate);
|
||
}
|
||
/* Bring the priority down to 0, so that it will be replaced
|
||
@@ -208,7 +240,7 @@ component_clean_turn_servers (Component *cmp)
|
||
discovery_prune_socket (cmp->agent, candidate->sockptr);
|
||
conn_check_prune_socket (cmp->agent, cmp->stream, cmp,
|
||
candidate->sockptr);
|
||
- component_detach_socket (cmp, candidate->sockptr);
|
||
+ nice_component_detach_socket (cmp, candidate->sockptr);
|
||
agent_remove_local_candidate (cmp->agent, candidate);
|
||
nice_candidate_free (candidate);
|
||
}
|
||
@@ -218,7 +250,7 @@ component_clean_turn_servers (Component *cmp)
|
||
}
|
||
|
||
static void
|
||
-component_clear_selected_pair (Component *component)
|
||
+nice_component_clear_selected_pair (NiceComponent *component)
|
||
{
|
||
if (component->selected_pair.keepalive.tick_source != NULL) {
|
||
g_source_destroy (component->selected_pair.keepalive.tick_source);
|
||
@@ -232,7 +264,7 @@ component_clear_selected_pair (Component *component)
|
||
/* Must be called with the agent lock held as it touches internal Component
|
||
* state. */
|
||
void
|
||
-component_close (Component *cmp)
|
||
+nice_component_close (NiceComponent *cmp)
|
||
{
|
||
IOCallbackData *data;
|
||
GOutputVector *vec;
|
||
@@ -240,13 +272,13 @@ component_close (Component *cmp)
|
||
/* Start closing the pseudo-TCP socket first. FIXME: There is a very big and
|
||
* reliably triggerable race here. pseudo_tcp_socket_close() does not block
|
||
* on the socket closing — it only sends the first packet of the FIN
|
||
- * handshake. component_close() will immediately afterwards close the
|
||
+ * handshake. nice_component_close() will immediately afterwards close the
|
||
* underlying component sockets, aborting the handshake.
|
||
*
|
||
* On the principle that starting the FIN handshake is better than not
|
||
* starting it, even if it’s later truncated, call pseudo_tcp_socket_close().
|
||
- * A long-term fix is needed in the form of making component_close() (and all
|
||
- * its callers) async, so we can properly block on closure. */
|
||
+ * A long-term fix is needed in the form of making nice_component_close() (and
|
||
+ * all its callers) async, so we can properly block on closure. */
|
||
if (cmp->tcp) {
|
||
pseudo_tcp_socket_close (cmp->tcp, TRUE);
|
||
}
|
||
@@ -269,12 +301,12 @@ component_close (Component *cmp)
|
||
g_slist_free_full (cmp->remote_candidates,
|
||
(GDestroyNotify) nice_candidate_free);
|
||
cmp->remote_candidates = NULL;
|
||
- component_free_socket_sources (cmp);
|
||
+ nice_component_free_socket_sources (cmp);
|
||
g_slist_free_full (cmp->incoming_checks,
|
||
(GDestroyNotify) incoming_check_free);
|
||
cmp->incoming_checks = NULL;
|
||
|
||
- component_clean_turn_servers (cmp);
|
||
+ nice_component_clean_turn_servers (cmp);
|
||
|
||
if (cmp->tcp_clock) {
|
||
g_source_destroy (cmp->tcp_clock);
|
||
@@ -289,7 +321,7 @@ component_close (Component *cmp)
|
||
while ((data = g_queue_pop_head (&cmp->pending_io_messages)) != NULL)
|
||
io_callback_data_free (data);
|
||
|
||
- component_deschedule_io_callback (cmp);
|
||
+ nice_component_deschedule_io_callback (cmp);
|
||
|
||
g_cancellable_cancel (cmp->stop_cancellable);
|
||
|
||
@@ -299,47 +331,13 @@ component_close (Component *cmp)
|
||
}
|
||
}
|
||
|
||
-/* Must be called with the agent lock released as it could dispose of
|
||
- * NiceIOStreams. */
|
||
-void
|
||
-component_free (Component *cmp)
|
||
-{
|
||
- /* Component should have been closed already. */
|
||
- g_warn_if_fail (cmp->local_candidates == NULL);
|
||
- g_warn_if_fail (cmp->remote_candidates == NULL);
|
||
- g_warn_if_fail (cmp->incoming_checks == NULL);
|
||
-
|
||
- g_clear_object (&cmp->tcp);
|
||
- g_clear_object (&cmp->stop_cancellable);
|
||
- g_clear_object (&cmp->iostream);
|
||
- g_mutex_clear (&cmp->io_mutex);
|
||
-
|
||
- if (cmp->stop_cancellable_source != NULL) {
|
||
- g_source_destroy (cmp->stop_cancellable_source);
|
||
- g_source_unref (cmp->stop_cancellable_source);
|
||
- }
|
||
-
|
||
- if (cmp->ctx != NULL) {
|
||
- g_main_context_unref (cmp->ctx);
|
||
- cmp->ctx = NULL;
|
||
- }
|
||
-
|
||
- g_main_context_unref (cmp->own_ctx);
|
||
-
|
||
- g_slice_free (Component, cmp);
|
||
-
|
||
- g_atomic_int_inc (&n_components_destroyed);
|
||
- nice_debug ("Destroyed NiceComponent (%u created, %u destroyed)",
|
||
- n_components_created, n_components_destroyed);
|
||
-}
|
||
-
|
||
/*
|
||
* Finds a candidate pair that has matching foundation ids.
|
||
*
|
||
* @return TRUE if pair found, pointer to pair stored at 'pair'
|
||
*/
|
||
gboolean
|
||
-component_find_pair (Component *cmp, NiceAgent *agent, const gchar *lfoundation, const gchar *rfoundation, CandidatePair *pair)
|
||
+nice_component_find_pair (NiceComponent *cmp, NiceAgent *agent, const gchar *lfoundation, const gchar *rfoundation, CandidatePair *pair)
|
||
{
|
||
GSList *i;
|
||
CandidatePair result = { 0, };
|
||
@@ -375,7 +373,7 @@ component_find_pair (Component *cmp, NiceAgent *agent, const gchar *lfoundation,
|
||
* session.
|
||
*/
|
||
void
|
||
-component_restart (Component *cmp)
|
||
+nice_component_restart (NiceComponent *cmp)
|
||
{
|
||
GSList *i;
|
||
|
||
@@ -410,7 +408,8 @@ component_restart (Component *cmp)
|
||
* Changes the selected pair for the component to 'pair'. Does not
|
||
* emit the "selected-pair-changed" signal.
|
||
*/
|
||
-void component_update_selected_pair (Component *component, const CandidatePair *pair)
|
||
+void
|
||
+nice_component_update_selected_pair (NiceComponent *component, const CandidatePair *pair)
|
||
{
|
||
g_assert (component);
|
||
g_assert (pair);
|
||
@@ -425,17 +424,17 @@ void component_update_selected_pair (Component *component, const CandidatePair *
|
||
component->turn_candidate->sockptr);
|
||
conn_check_prune_socket (component->agent, component->stream, component,
|
||
component->turn_candidate->sockptr);
|
||
- component_detach_socket (component, component->turn_candidate->sockptr);
|
||
+ nice_component_detach_socket (component, component->turn_candidate->sockptr);
|
||
nice_candidate_free (component->turn_candidate);
|
||
component->turn_candidate = NULL;
|
||
}
|
||
|
||
- component_clear_selected_pair (component);
|
||
+ nice_component_clear_selected_pair (component);
|
||
|
||
component->selected_pair.local = pair->local;
|
||
component->selected_pair.remote = pair->remote;
|
||
component->selected_pair.priority = pair->priority;
|
||
-
|
||
+ component->selected_pair.prflx_priority = pair->prflx_priority;
|
||
}
|
||
|
||
/*
|
||
@@ -445,7 +444,7 @@ void component_update_selected_pair (Component *component, const CandidatePair *
|
||
* @return pointer to candidate or NULL if not found
|
||
*/
|
||
NiceCandidate *
|
||
-component_find_remote_candidate (const Component *component, const NiceAddress *addr, NiceCandidateTransport transport)
|
||
+nice_component_find_remote_candidate (NiceComponent *component, const NiceAddress *addr, NiceCandidateTransport transport)
|
||
{
|
||
GSList *i;
|
||
|
||
@@ -469,8 +468,8 @@ component_find_remote_candidate (const Component *component, const NiceAddress *
|
||
*/
|
||
|
||
NiceCandidate *
|
||
-component_set_selected_remote_candidate (NiceAgent *agent, Component *component,
|
||
- NiceCandidate *candidate)
|
||
+nice_component_set_selected_remote_candidate (NiceComponent *component,
|
||
+ NiceAgent *agent, NiceCandidate *candidate)
|
||
{
|
||
NiceCandidate *local = NULL;
|
||
NiceCandidate *remote = NULL;
|
||
@@ -483,7 +482,7 @@ component_set_selected_remote_candidate (NiceAgent *agent, Component *component,
|
||
NiceCandidate *tmp = item->data;
|
||
guint64 tmp_prio = 0;
|
||
|
||
- if (tmp->transport != candidate->transport ||
|
||
+ if (tmp->transport != conn_check_match_transport(candidate->transport) ||
|
||
tmp->addr.s.addr.sa_family != candidate->addr.s.addr.sa_family ||
|
||
tmp->type != NICE_CANDIDATE_TYPE_HOST)
|
||
continue;
|
||
@@ -499,7 +498,7 @@ component_set_selected_remote_candidate (NiceAgent *agent, Component *component,
|
||
if (local == NULL)
|
||
return NULL;
|
||
|
||
- remote = component_find_remote_candidate (component, &candidate->addr,
|
||
+ remote = nice_component_find_remote_candidate (component, &candidate->addr,
|
||
candidate->transport);
|
||
|
||
if (!remote) {
|
||
@@ -509,7 +508,7 @@ component_set_selected_remote_candidate (NiceAgent *agent, Component *component,
|
||
agent_signal_new_remote_candidate (agent, remote);
|
||
}
|
||
|
||
- component_clear_selected_pair (component);
|
||
+ nice_component_clear_selected_pair (component);
|
||
|
||
component->selected_pair.local = local;
|
||
component->selected_pair.remote = remote;
|
||
@@ -530,7 +529,7 @@ _find_socket_source (gconstpointer a, gconstpointer b)
|
||
/* This takes ownership of the socket.
|
||
* It creates and attaches a source to the component’s context. */
|
||
void
|
||
-component_attach_socket (Component *component, NiceSocket *nicesock)
|
||
+nice_component_attach_socket (NiceComponent *component, NiceSocket *nicesock)
|
||
{
|
||
GSList *l;
|
||
SocketSource *socket_source;
|
||
@@ -540,9 +539,6 @@ component_attach_socket (Component *component, NiceSocket *nicesock)
|
||
|
||
g_assert (component->ctx != NULL);
|
||
|
||
- if (nicesock->fileno == NULL)
|
||
- return;
|
||
-
|
||
/* Find an existing SocketSource in the component which contains @socket, or
|
||
* create a new one.
|
||
*
|
||
@@ -559,7 +555,8 @@ component_attach_socket (Component *component, NiceSocket *nicesock)
|
||
socket_source->component = component;
|
||
component->socket_sources =
|
||
g_slist_prepend (component->socket_sources, socket_source);
|
||
- component->socket_sources_age++;
|
||
+ if (nicesock->fileno != NULL)
|
||
+ component->socket_sources_age++;
|
||
}
|
||
|
||
/* Create and attach a source */
|
||
@@ -571,9 +568,9 @@ component_attach_socket (Component *component, NiceSocket *nicesock)
|
||
/* Reattaches socket handles of @component to the main context.
|
||
*
|
||
* Must *not* take the agent lock, since it’s called from within
|
||
- * component_set_io_context(), which holds the Component’s I/O lock. */
|
||
+ * nice_component_set_io_context(), which holds the Component’s I/O lock. */
|
||
static void
|
||
-component_reattach_all_sockets (Component *component)
|
||
+nice_component_reattach_all_sockets (NiceComponent *component)
|
||
{
|
||
GSList *i;
|
||
|
||
@@ -586,8 +583,8 @@ component_reattach_all_sockets (Component *component)
|
||
}
|
||
|
||
/**
|
||
- * component_detach_socket:
|
||
- * @component: a #Component
|
||
+ * nice_component_detach_socket:
|
||
+ * @component: a #NiceComponent
|
||
* @socket: the socket to detach the source for
|
||
*
|
||
* Detach the #GSource for the single specified @socket. It also closes it
|
||
@@ -595,8 +592,8 @@ component_reattach_all_sockets (Component *component)
|
||
*
|
||
* If the @socket doesn’t exist in this @component, do nothing.
|
||
*/
|
||
-void
|
||
-component_detach_socket (Component *component, NiceSocket *nicesock)
|
||
+static void
|
||
+nice_component_detach_socket (NiceComponent *component, NiceSocket *nicesock)
|
||
{
|
||
GSList *l;
|
||
SocketSource *socket_source;
|
||
@@ -637,10 +634,10 @@ component_detach_socket (Component *component, NiceSocket *nicesock)
|
||
* sockets themselves untouched.
|
||
*
|
||
* Must *not* take the agent lock, since it’s called from within
|
||
- * component_set_io_context(), which holds the Component’s I/O lock.
|
||
+ * nice_component_set_io_context(), which holds the Component’s I/O lock.
|
||
*/
|
||
void
|
||
-component_detach_all_sockets (Component *component)
|
||
+nice_component_detach_all_sockets (NiceComponent *component)
|
||
{
|
||
GSList *i;
|
||
|
||
@@ -653,7 +650,7 @@ component_detach_all_sockets (Component *component)
|
||
}
|
||
|
||
void
|
||
-component_free_socket_sources (Component *component)
|
||
+nice_component_free_socket_sources (NiceComponent *component)
|
||
{
|
||
nice_debug ("Free socket sources for component %p.", component);
|
||
|
||
@@ -662,11 +659,11 @@ component_free_socket_sources (Component *component)
|
||
component->socket_sources = NULL;
|
||
component->socket_sources_age++;
|
||
|
||
- component_clear_selected_pair (component);
|
||
+ nice_component_clear_selected_pair (component);
|
||
}
|
||
|
||
GMainContext *
|
||
-component_dup_io_context (Component *component)
|
||
+nice_component_dup_io_context (NiceComponent *component)
|
||
{
|
||
return g_main_context_ref (component->own_ctx);
|
||
}
|
||
@@ -674,7 +671,7 @@ component_dup_io_context (Component *component)
|
||
/* If @context is %NULL, it's own context is used, so component->ctx is always
|
||
* guaranteed to be non-%NULL. */
|
||
void
|
||
-component_set_io_context (Component *component, GMainContext *context)
|
||
+nice_component_set_io_context (NiceComponent *component, GMainContext *context)
|
||
{
|
||
g_mutex_lock (&component->io_mutex);
|
||
|
||
@@ -684,11 +681,11 @@ component_set_io_context (Component *component, GMainContext *context)
|
||
else
|
||
g_main_context_ref (context);
|
||
|
||
- component_detach_all_sockets (component);
|
||
+ nice_component_detach_all_sockets (component);
|
||
g_main_context_unref (component->ctx);
|
||
|
||
component->ctx = context;
|
||
- component_reattach_all_sockets (component);
|
||
+ nice_component_reattach_all_sockets (component);
|
||
}
|
||
|
||
g_mutex_unlock (&component->io_mutex);
|
||
@@ -705,7 +702,7 @@ component_set_io_context (Component *component, GMainContext *context)
|
||
* emitted for it (which could cause data loss if the I/O callback function was
|
||
* unset in that time). */
|
||
void
|
||
-component_set_io_callback (Component *component,
|
||
+nice_component_set_io_callback (NiceComponent *component,
|
||
NiceAgentRecvFunc func, gpointer user_data,
|
||
NiceInputMessage *recv_messages, guint n_recv_messages,
|
||
GError **error)
|
||
@@ -722,14 +719,14 @@ component_set_io_callback (Component *component,
|
||
component->recv_messages = NULL;
|
||
component->n_recv_messages = 0;
|
||
|
||
- component_schedule_io_callback (component);
|
||
+ nice_component_schedule_io_callback (component);
|
||
} else {
|
||
component->io_callback = NULL;
|
||
component->io_user_data = NULL;
|
||
component->recv_messages = recv_messages;
|
||
component->n_recv_messages = n_recv_messages;
|
||
|
||
- component_deschedule_io_callback (component);
|
||
+ nice_component_deschedule_io_callback (component);
|
||
}
|
||
|
||
nice_input_message_iter_reset (&component->recv_messages_iter);
|
||
@@ -739,7 +736,7 @@ component_set_io_callback (Component *component,
|
||
}
|
||
|
||
gboolean
|
||
-component_has_io_callback (Component *component)
|
||
+nice_component_has_io_callback (NiceComponent *component)
|
||
{
|
||
gboolean has_io_callback;
|
||
|
||
@@ -775,7 +772,7 @@ io_callback_data_free (IOCallbackData *data)
|
||
static gboolean
|
||
emit_io_callback_cb (gpointer user_data)
|
||
{
|
||
- Component *component = user_data;
|
||
+ NiceComponent *component = user_data;
|
||
IOCallbackData *data;
|
||
NiceAgentRecvFunc io_callback;
|
||
gpointer io_user_data;
|
||
@@ -792,7 +789,7 @@ emit_io_callback_cb (gpointer user_data)
|
||
g_mutex_lock (&component->io_mutex);
|
||
|
||
/* The members of Component are guaranteed not to have changed since this
|
||
- * GSource was attached in component_emit_io_callback(). The Component’s agent
|
||
+ * GSource was attached in nice_component_emit_io_callback(). The Component’s agent
|
||
* and stream are immutable after construction, as are the stream and
|
||
* component IDs. The callback and its user data may have changed, but are
|
||
* guaranteed to be non-%NULL at the start as the idle source is removed when
|
||
@@ -802,7 +799,7 @@ emit_io_callback_cb (gpointer user_data)
|
||
*
|
||
* If the component is destroyed (which happens if the agent or stream are
|
||
* destroyed) between attaching the GSource and firing it, the GSource is
|
||
- * detached in component_free() and this callback is never invoked. If the
|
||
+ * detached during dispose and this callback is never invoked. If the
|
||
* agent is destroyed during an io_callback, its weak pointer will be
|
||
* nullified. Similarly, the Component needs to be re-queried for after every
|
||
* iteration, just in case the client has removed the stream in the
|
||
@@ -845,7 +842,7 @@ emit_io_callback_cb (gpointer user_data)
|
||
|
||
/* This must be called with the agent lock *held*. */
|
||
void
|
||
-component_emit_io_callback (Component *component,
|
||
+nice_component_emit_io_callback (NiceComponent *component,
|
||
const guint8 *buf, gsize buf_len)
|
||
{
|
||
NiceAgent *agent;
|
||
@@ -897,7 +894,7 @@ component_emit_io_callback (Component *component,
|
||
|
||
nice_debug ("%s: **WARNING: SLOW PATH**", G_STRFUNC);
|
||
|
||
- component_schedule_io_callback (component);
|
||
+ nice_component_schedule_io_callback (component);
|
||
|
||
g_mutex_unlock (&component->io_mutex);
|
||
}
|
||
@@ -905,7 +902,7 @@ component_emit_io_callback (Component *component,
|
||
|
||
/* Note: Must be called with the io_mutex held. */
|
||
static void
|
||
-component_schedule_io_callback (Component *component)
|
||
+nice_component_schedule_io_callback (NiceComponent *component)
|
||
{
|
||
GSource *source;
|
||
|
||
@@ -928,7 +925,7 @@ component_schedule_io_callback (Component *component)
|
||
|
||
/* Note: Must be called with the io_mutex held. */
|
||
static void
|
||
-component_deschedule_io_callback (Component *component)
|
||
+nice_component_deschedule_io_callback (NiceComponent *component)
|
||
{
|
||
/* Already descheduled? */
|
||
if (component->io_callback_id == 0)
|
||
@@ -938,6 +935,202 @@ component_deschedule_io_callback (Component *component)
|
||
component->io_callback_id = 0;
|
||
}
|
||
|
||
+static void
|
||
+nice_component_class_init (NiceComponentClass *klass)
|
||
+{
|
||
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||
+
|
||
+ object_class->constructed = nice_component_constructed;
|
||
+ object_class->get_property = nice_component_get_property;
|
||
+ object_class->set_property = nice_component_set_property;
|
||
+ object_class->finalize = nice_component_finalize;
|
||
+
|
||
+ /**
|
||
+ * NiceComponent:id:
|
||
+ *
|
||
+ * The unique numeric ID of the component.
|
||
+ *
|
||
+ * Since: UNRELEASED
|
||
+ */
|
||
+ g_object_class_install_property (object_class, PROP_ID,
|
||
+ g_param_spec_uint (
|
||
+ "id",
|
||
+ "ID",
|
||
+ "The unique numeric ID of the component.",
|
||
+ 1, G_MAXUINT, 1,
|
||
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||
+
|
||
+ /**
|
||
+ * NiceComponent:agent:
|
||
+ *
|
||
+ * The #NiceAgent this component belongs to.
|
||
+ *
|
||
+ * Since: UNRELEASED
|
||
+ */
|
||
+ g_object_class_install_property (object_class, PROP_AGENT,
|
||
+ g_param_spec_object (
|
||
+ "agent",
|
||
+ "Agent",
|
||
+ "The NiceAgent this component belongs to.",
|
||
+ NICE_TYPE_AGENT,
|
||
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||
+
|
||
+ /**
|
||
+ * NiceComponent:stream:
|
||
+ *
|
||
+ * The #NiceStream this component belongs to.
|
||
+ *
|
||
+ * Since: UNRELEASED
|
||
+ */
|
||
+ g_object_class_install_property (object_class, PROP_STREAM,
|
||
+ g_param_spec_object (
|
||
+ "stream",
|
||
+ "Stream",
|
||
+ "The NiceStream this component belongs to.",
|
||
+ NICE_TYPE_STREAM,
|
||
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||
+}
|
||
+
|
||
+static void
|
||
+nice_component_init (NiceComponent *component)
|
||
+{
|
||
+ g_atomic_int_inc (&n_components_created);
|
||
+ nice_debug ("Created NiceComponent (%u created, %u destroyed)",
|
||
+ n_components_created, n_components_destroyed);
|
||
+
|
||
+ component->id = 0;
|
||
+ component->state = NICE_COMPONENT_STATE_DISCONNECTED;
|
||
+ component->restart_candidate = NULL;
|
||
+ component->tcp = NULL;
|
||
+ component->agent = NULL;
|
||
+ component->stream = NULL;
|
||
+
|
||
+ g_mutex_init (&component->io_mutex);
|
||
+ g_queue_init (&component->pending_io_messages);
|
||
+ component->io_callback_id = 0;
|
||
+
|
||
+ component->own_ctx = g_main_context_new ();
|
||
+ component->stop_cancellable = g_cancellable_new ();
|
||
+ component->stop_cancellable_source =
|
||
+ g_cancellable_source_new (component->stop_cancellable);
|
||
+ g_source_set_dummy_callback (component->stop_cancellable_source);
|
||
+ g_source_attach (component->stop_cancellable_source, component->own_ctx);
|
||
+ component->ctx = g_main_context_ref (component->own_ctx);
|
||
+
|
||
+ /* Start off with a fresh main context and all I/O paused. This
|
||
+ * will be updated when nice_agent_attach_recv() or nice_agent_recv_messages()
|
||
+ * are called. */
|
||
+ nice_component_set_io_context (component, NULL);
|
||
+ nice_component_set_io_callback (component, NULL, NULL, NULL, 0, NULL);
|
||
+
|
||
+ g_queue_init (&component->queued_tcp_packets);
|
||
+}
|
||
+
|
||
+static void
|
||
+nice_component_constructed (GObject *obj)
|
||
+{
|
||
+ NiceComponent *component;
|
||
+
|
||
+ component = NICE_COMPONENT (obj);
|
||
+
|
||
+ g_assert (component->agent != NULL);
|
||
+ nice_agent_init_stun_agent (component->agent, &component->stun_agent);
|
||
+
|
||
+ G_OBJECT_CLASS (nice_component_parent_class)->constructed (obj);
|
||
+}
|
||
+
|
||
+static void
|
||
+nice_component_get_property (GObject *obj,
|
||
+ guint property_id, GValue *value, GParamSpec *pspec)
|
||
+{
|
||
+ NiceComponent *component;
|
||
+
|
||
+ component = NICE_COMPONENT (obj);
|
||
+
|
||
+ switch ((NiceComponentProperty) property_id)
|
||
+ {
|
||
+ case PROP_ID:
|
||
+ g_value_set_uint (value, component->id);
|
||
+ break;
|
||
+
|
||
+ case PROP_AGENT:
|
||
+ g_value_set_object (value, component->agent);
|
||
+ break;
|
||
+
|
||
+ case PROP_STREAM:
|
||
+ g_value_set_object (value, component->stream);
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
|
||
+ }
|
||
+}
|
||
+
|
||
+static void
|
||
+nice_component_set_property (GObject *obj,
|
||
+ guint property_id, const GValue *value, GParamSpec *pspec)
|
||
+{
|
||
+ NiceComponent *component;
|
||
+
|
||
+ component = NICE_COMPONENT (obj);
|
||
+
|
||
+ switch ((NiceComponentProperty) property_id)
|
||
+ {
|
||
+ case PROP_ID:
|
||
+ component->id = g_value_get_uint (value);
|
||
+ break;
|
||
+
|
||
+ case PROP_AGENT:
|
||
+ component->agent = g_value_get_object (value);
|
||
+ break;
|
||
+
|
||
+ case PROP_STREAM:
|
||
+ component->stream = g_value_get_object (value);
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
|
||
+ }
|
||
+}
|
||
+
|
||
+/* Must be called with the agent lock released as it could dispose of
|
||
+ * NiceIOStreams. */
|
||
+static void
|
||
+nice_component_finalize (GObject *obj)
|
||
+{
|
||
+ NiceComponent *cmp;
|
||
+
|
||
+ cmp = NICE_COMPONENT (obj);
|
||
+
|
||
+ /* Component should have been closed already. */
|
||
+ g_warn_if_fail (cmp->local_candidates == NULL);
|
||
+ g_warn_if_fail (cmp->remote_candidates == NULL);
|
||
+ g_warn_if_fail (cmp->incoming_checks == NULL);
|
||
+
|
||
+ g_clear_object (&cmp->tcp);
|
||
+ g_clear_object (&cmp->stop_cancellable);
|
||
+ g_clear_object (&cmp->iostream);
|
||
+ g_mutex_clear (&cmp->io_mutex);
|
||
+
|
||
+ if (cmp->stop_cancellable_source != NULL) {
|
||
+ g_source_destroy (cmp->stop_cancellable_source);
|
||
+ g_source_unref (cmp->stop_cancellable_source);
|
||
+ }
|
||
+
|
||
+ if (cmp->ctx != NULL) {
|
||
+ g_main_context_unref (cmp->ctx);
|
||
+ cmp->ctx = NULL;
|
||
+ }
|
||
+
|
||
+ g_main_context_unref (cmp->own_ctx);
|
||
+
|
||
+ g_atomic_int_inc (&n_components_destroyed);
|
||
+ nice_debug ("Destroyed NiceComponent (%u created, %u destroyed)",
|
||
+ n_components_created, n_components_destroyed);
|
||
+
|
||
+ G_OBJECT_CLASS (nice_component_parent_class)->finalize (obj);
|
||
+}
|
||
+
|
||
/**
|
||
* ComponentSource:
|
||
*
|
||
@@ -980,7 +1173,7 @@ component_source_prepare (GSource *source, gint *timeout_)
|
||
{
|
||
ComponentSource *component_source = (ComponentSource *) source;
|
||
NiceAgent *agent;
|
||
- Component *component;
|
||
+ NiceComponent *component;
|
||
GSList *parentl, *childl;
|
||
|
||
agent = g_weak_ref_get (&component_source->agent_ref);
|
||
@@ -1011,6 +1204,9 @@ component_source_prepare (GSource *source, gint *timeout_)
|
||
SocketSource *parent_socket_source = parentl->data;
|
||
SocketSource *child_socket_source;
|
||
|
||
+ if (parent_socket_source->socket->fileno == NULL)
|
||
+ continue;
|
||
+
|
||
/* Iterating the list of socket sources every time isn't a big problem
|
||
* because the number of pairs is limited ~100 normally, so there will
|
||
* rarely be more than 10.
|
||
@@ -1128,7 +1324,7 @@ static GSourceFuncs component_source_funcs = {
|
||
};
|
||
|
||
/**
|
||
- * component_source_new:
|
||
+ * nice_component_source_new:
|
||
* @agent: a #NiceAgent
|
||
* @stream_id: The stream's id
|
||
* @component_id: The component's number
|
||
@@ -1150,7 +1346,7 @@ static GSourceFuncs component_source_funcs = {
|
||
* Returns: (transfer full): a new #ComponentSource; unref with g_source_unref()
|
||
*/
|
||
GSource *
|
||
-component_input_source_new (NiceAgent *agent, guint stream_id,
|
||
+nice_component_input_source_new (NiceAgent *agent, guint stream_id,
|
||
guint component_id, GPollableInputStream *pollable_istream,
|
||
GCancellable *cancellable)
|
||
{
|
||
diff --git a/agent/component.h b/agent/component.h
|
||
index 7ded710..6712794 100644
|
||
--- a/agent/component.h
|
||
+++ b/agent/component.h
|
||
@@ -42,7 +42,7 @@
|
||
|
||
#include <glib.h>
|
||
|
||
-typedef struct _Component Component;
|
||
+typedef struct _NiceComponent NiceComponent;
|
||
|
||
#include "agent.h"
|
||
#include "agent-priv.h"
|
||
@@ -83,6 +83,7 @@ struct _CandidatePair
|
||
NiceCandidate *local;
|
||
NiceCandidate *remote;
|
||
guint64 priority; /* candidate pair priority */
|
||
+ guint32 prflx_priority;
|
||
CandidatePairKeepalive keepalive;
|
||
};
|
||
|
||
@@ -110,7 +111,7 @@ incoming_check_free (IncomingCheck *icheck);
|
||
typedef struct {
|
||
NiceSocket *socket;
|
||
GSource *source;
|
||
- Component *component;
|
||
+ NiceComponent *component;
|
||
} SocketSource;
|
||
|
||
|
||
@@ -137,9 +138,22 @@ io_callback_data_new (const guint8 *buf, gsize buf_len);
|
||
void
|
||
io_callback_data_free (IOCallbackData *data);
|
||
|
||
+#define NICE_TYPE_COMPONENT nice_component_get_type()
|
||
+#define NICE_COMPONENT(obj) \
|
||
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NICE_TYPE_COMPONENT, NiceComponent))
|
||
+#define NICE_COMPONENT_CLASS(klass) \
|
||
+ (G_TYPE_CHECK_CLASS_CAST ((klass), NICE_TYPE_COMPONENT, NiceComponentClass))
|
||
+#define NICE_IS_COMPONENT(obj) \
|
||
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NICE_TYPE_COMPONENT))
|
||
+#define NICE_IS_COMPONENT_CLASS(klass) \
|
||
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), NICE_TYPE_COMPONENT))
|
||
+#define NICE_COMPONENT_GET_CLASS(obj) \
|
||
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), NICE_TYPE_COMPONENT, NiceComponentClass))
|
||
+
|
||
+struct _NiceComponent {
|
||
+ /*< private >*/
|
||
+ GObject parent;
|
||
|
||
-struct _Component
|
||
-{
|
||
NiceComponentType type;
|
||
guint id; /* component id */
|
||
NiceComponentState state;
|
||
@@ -186,8 +200,8 @@ struct _Component
|
||
|
||
NiceAgent *agent; /* unowned, immutable: can be accessed without holding the
|
||
* agent lock */
|
||
- Stream *stream; /* unowned, immutable: can be accessed without holding the
|
||
- * agent lock */
|
||
+ NiceStream *stream; /* unowned, immutable: can be accessed without holding
|
||
+ * the agent lock */
|
||
|
||
StunAgent stun_agent; /* This stun agent is used to validate all stun requests */
|
||
|
||
@@ -212,63 +226,69 @@ struct _Component
|
||
GQueue queued_tcp_packets;
|
||
};
|
||
|
||
-Component *
|
||
-component_new (guint component_id, NiceAgent *agent, Stream *stream);
|
||
+typedef struct {
|
||
+ GObjectClass parent_class;
|
||
+} NiceComponentClass;
|
||
+
|
||
+GType nice_component_get_type (void);
|
||
|
||
-void
|
||
-component_close (Component *cmp);
|
||
+NiceComponent *
|
||
+nice_component_new (guint component_id, NiceAgent *agent, NiceStream *stream);
|
||
|
||
void
|
||
-component_free (Component *cmp);
|
||
+nice_component_close (NiceComponent *component);
|
||
|
||
gboolean
|
||
-component_find_pair (Component *cmp, NiceAgent *agent, const gchar *lfoundation, const gchar *rfoundation, CandidatePair *pair);
|
||
+nice_component_find_pair (NiceComponent *component, NiceAgent *agent,
|
||
+ const gchar *lfoundation, const gchar *rfoundation, CandidatePair *pair);
|
||
|
||
void
|
||
-component_restart (Component *cmp);
|
||
+nice_component_restart (NiceComponent *component);
|
||
|
||
void
|
||
-component_update_selected_pair (Component *component, const CandidatePair *pair);
|
||
+nice_component_update_selected_pair (NiceComponent *component,
|
||
+ const CandidatePair *pair);
|
||
|
||
NiceCandidate *
|
||
-component_find_remote_candidate (const Component *component, const NiceAddress *addr, NiceCandidateTransport transport);
|
||
+nice_component_find_remote_candidate (NiceComponent *component,
|
||
+ const NiceAddress *addr, NiceCandidateTransport transport);
|
||
|
||
NiceCandidate *
|
||
-component_set_selected_remote_candidate (NiceAgent *agent, Component *component,
|
||
- NiceCandidate *candidate);
|
||
+nice_component_set_selected_remote_candidate (NiceComponent *component,
|
||
+ NiceAgent *agent, NiceCandidate *candidate);
|
||
|
||
void
|
||
-component_attach_socket (Component *component, NiceSocket *nsocket);
|
||
+nice_component_attach_socket (NiceComponent *component, NiceSocket *nsocket);
|
||
+
|
||
void
|
||
-component_detach_socket (Component *component, NiceSocket *nsocket);
|
||
+nice_component_remove_socket (NiceComponent *component, NiceSocket *nsocket);
|
||
void
|
||
-component_detach_all_sockets (Component *component);
|
||
+nice_component_detach_all_sockets (NiceComponent *component);
|
||
+
|
||
void
|
||
-component_free_socket_sources (Component *component);
|
||
+nice_component_free_socket_sources (NiceComponent *component);
|
||
|
||
GSource *
|
||
-component_input_source_new (NiceAgent *agent, guint stream_id,
|
||
+nice_component_input_source_new (NiceAgent *agent, guint stream_id,
|
||
guint component_id, GPollableInputStream *pollable_istream,
|
||
GCancellable *cancellable);
|
||
|
||
GMainContext *
|
||
-component_dup_io_context (Component *component);
|
||
+nice_component_dup_io_context (NiceComponent *component);
|
||
void
|
||
-component_set_io_context (Component *component, GMainContext *context);
|
||
+nice_component_set_io_context (NiceComponent *component, GMainContext *context);
|
||
void
|
||
-component_set_io_callback (Component *component,
|
||
+nice_component_set_io_callback (NiceComponent *component,
|
||
NiceAgentRecvFunc func, gpointer user_data,
|
||
NiceInputMessage *recv_messages, guint n_recv_messages,
|
||
GError **error);
|
||
void
|
||
-component_emit_io_callback (Component *component,
|
||
+nice_component_emit_io_callback (NiceComponent *component,
|
||
const guint8 *buf, gsize buf_len);
|
||
-
|
||
gboolean
|
||
-component_has_io_callback (Component *component);
|
||
-
|
||
+nice_component_has_io_callback (NiceComponent *component);
|
||
void
|
||
-component_clean_turn_servers (Component *component);
|
||
+nice_component_clean_turn_servers (NiceComponent *component);
|
||
|
||
|
||
TurnServer *
|
||
diff --git a/agent/conncheck.c b/agent/conncheck.c
|
||
index 057fc81..7e03985 100644
|
||
--- a/agent/conncheck.c
|
||
+++ b/agent/conncheck.c
|
||
@@ -61,18 +61,20 @@
|
||
#include "stun/usages/bind.h"
|
||
#include "stun/usages/turn.h"
|
||
|
||
-static void priv_update_check_list_failed_components (NiceAgent *agent, Stream *stream);
|
||
-static void priv_update_check_list_state_for_ready (NiceAgent *agent, Stream *stream, Component *component);
|
||
-static guint priv_prune_pending_checks (Stream *stream, guint component_id);
|
||
-static gboolean priv_schedule_triggered_check (NiceAgent *agent, Stream *stream, Component *component, NiceSocket *local_socket, NiceCandidate *remote_cand, gboolean use_candidate);
|
||
-static void priv_mark_pair_nominated (NiceAgent *agent, Stream *stream, Component *component, NiceCandidate *remotecand);
|
||
-static size_t priv_create_username (NiceAgent *agent, Stream *stream,
|
||
+static void priv_update_check_list_failed_components (NiceAgent *agent, NiceStream *stream);
|
||
+static void priv_update_check_list_state_for_ready (NiceAgent *agent, NiceStream *stream, NiceComponent *component);
|
||
+static guint priv_prune_pending_checks (NiceStream *stream, guint component_id);
|
||
+static gboolean priv_schedule_triggered_check (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceSocket *local_socket, NiceCandidate *remote_cand, gboolean use_candidate);
|
||
+static void priv_mark_pair_nominated (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceCandidate *localcand, NiceCandidate *remotecand);
|
||
+static size_t priv_create_username (NiceAgent *agent, NiceStream *stream,
|
||
guint component_id, NiceCandidate *remote, NiceCandidate *local,
|
||
uint8_t *dest, guint dest_len, gboolean inbound);
|
||
-static size_t priv_get_password (NiceAgent *agent, Stream *stream,
|
||
+static size_t priv_get_password (NiceAgent *agent, NiceStream *stream,
|
||
NiceCandidate *remote, uint8_t **password);
|
||
static void conn_check_free_item (gpointer data);
|
||
-static void priv_conn_check_add_for_candidate_pair_matched (NiceAgent *agent, guint stream_id, Component *component, NiceCandidate *local, NiceCandidate *remote, NiceCheckState initial_state);
|
||
+static CandidateCheckPair *priv_conn_check_add_for_candidate_pair_matched (
|
||
+ NiceAgent *agent, guint stream_id, NiceComponent *component,
|
||
+ NiceCandidate *local, NiceCandidate *remote, NiceCheckState initial_state);
|
||
|
||
static int priv_timer_expired (GTimeVal *timer, GTimeVal *now)
|
||
{
|
||
@@ -81,6 +83,140 @@ static int priv_timer_expired (GTimeVal *timer, GTimeVal *now)
|
||
now->tv_sec >= timer->tv_sec;
|
||
}
|
||
|
||
+static gchar
|
||
+priv_state_to_gchar (NiceCheckState state)
|
||
+{
|
||
+ switch (state) {
|
||
+ case NICE_CHECK_WAITING:
|
||
+ return 'W';
|
||
+ case NICE_CHECK_IN_PROGRESS:
|
||
+ return 'I';
|
||
+ case NICE_CHECK_SUCCEEDED:
|
||
+ return 'S';
|
||
+ case NICE_CHECK_FAILED:
|
||
+ return 'F';
|
||
+ case NICE_CHECK_FROZEN:
|
||
+ return 'Z';
|
||
+ case NICE_CHECK_CANCELLED:
|
||
+ return 'C';
|
||
+ case NICE_CHECK_DISCOVERED:
|
||
+ return 'D';
|
||
+ default:
|
||
+ g_assert_not_reached ();
|
||
+ }
|
||
+}
|
||
+
|
||
+static const gchar *
|
||
+priv_candidate_type_to_string (NiceCandidateType type)
|
||
+{
|
||
+ switch (type) {
|
||
+ case NICE_CANDIDATE_TYPE_HOST:
|
||
+ return "host";
|
||
+ case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
|
||
+ return "srflx";
|
||
+ case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
|
||
+ return "prflx";
|
||
+ case NICE_CANDIDATE_TYPE_RELAYED:
|
||
+ return "relay";
|
||
+ default:
|
||
+ g_assert_not_reached ();
|
||
+ }
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Dump the conncheck lists of the agent
|
||
+ */
|
||
+static void
|
||
+priv_print_conn_check_lists (NiceAgent *agent, const gchar *where, const gchar *detail)
|
||
+{
|
||
+ GSList *i, *k;
|
||
+ guint j;
|
||
+
|
||
+ if (!nice_debug_is_verbose ())
|
||
+ return;
|
||
+
|
||
+#define PRIORITY_LEN 32
|
||
+
|
||
+ nice_debug ("Agent %p : *** conncheck list DUMP (called from %s%s)",
|
||
+ agent, where, detail ? detail : "");
|
||
+ for (i = agent->streams; i ; i = i->next) {
|
||
+ NiceStream *stream = i->data;
|
||
+ for (j = 1; j <= stream->n_components; j++) {
|
||
+ for (k = stream->conncheck_list; k ; k = k->next) {
|
||
+ CandidateCheckPair *pair = k->data;
|
||
+ if (pair->component_id == j) {
|
||
+ gchar priority[PRIORITY_LEN];
|
||
+ guint p1, p2, p3;
|
||
+ gchar local_addr[INET6_ADDRSTRLEN];
|
||
+ gchar remote_addr[INET6_ADDRSTRLEN];
|
||
+
|
||
+ p1 = (pair->priority >> 32);
|
||
+ p2 = (pair->priority >> 1) & 0x7fffffff;
|
||
+ p3 = (pair->priority & 1);
|
||
+
|
||
+ g_snprintf (priority, PRIORITY_LEN,
|
||
+ "%02x:%04x:%02x:%02x:%04x:%02x:%1x",
|
||
+ (p1 >> 24) & 0x7f, (p1 >> 8) & 0xffff, (p1 & 0xff),
|
||
+ (p2 >> 24) & 0x7f, (p2 >> 8) & 0xffff, (p2 & 0xff),
|
||
+ p3);
|
||
+
|
||
+ nice_address_to_string (&pair->local->addr, local_addr);
|
||
+ nice_address_to_string (&pair->remote->addr, remote_addr);
|
||
+
|
||
+ nice_debug ("Agent %p : *** sc=%d/%d : pair %p : "
|
||
+ "f=%s t=%s:%s p=%s [%s]:%u > [%s]:%u state=%c%s%s%s",
|
||
+ agent, pair->stream_id, pair->component_id, pair,
|
||
+ pair->foundation,
|
||
+ priv_candidate_type_to_string (pair->local->type),
|
||
+ priv_candidate_type_to_string (pair->remote->type),
|
||
+ priority,
|
||
+ local_addr, nice_address_get_port (&pair->local->addr),
|
||
+ remote_addr, nice_address_get_port (&pair->remote->addr),
|
||
+ priv_state_to_gchar (pair->state),
|
||
+ pair->valid ? "V" : "",
|
||
+ pair->nominated ? "N" : "",
|
||
+ g_slist_find (agent->triggered_check_queue, pair) ? "T" : "");
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+/* Add the pair to the triggered checks list, if not already present
|
||
+ */
|
||
+static void
|
||
+priv_add_pair_to_triggered_check_queue (NiceAgent *agent, CandidateCheckPair *pair)
|
||
+{
|
||
+ g_assert (pair);
|
||
+
|
||
+ if (agent->triggered_check_queue == NULL ||
|
||
+ g_slist_find (agent->triggered_check_queue, pair) == NULL)
|
||
+ agent->triggered_check_queue = g_slist_append (agent->triggered_check_queue, pair);
|
||
+}
|
||
+
|
||
+/* Remove the pair from the triggered checks list
|
||
+ */
|
||
+static void
|
||
+priv_remove_pair_from_triggered_check_queue (NiceAgent *agent, CandidateCheckPair *pair)
|
||
+{
|
||
+ g_assert (pair);
|
||
+ agent->triggered_check_queue = g_slist_remove (agent->triggered_check_queue, pair);
|
||
+}
|
||
+
|
||
+/* Get the pair from the triggered checks list
|
||
+ */
|
||
+static CandidateCheckPair *
|
||
+priv_get_pair_from_triggered_check_queue (NiceAgent *agent)
|
||
+{
|
||
+ CandidateCheckPair *pair = NULL;
|
||
+
|
||
+ if (agent->triggered_check_queue) {
|
||
+ pair = (CandidateCheckPair *)agent->triggered_check_queue->data;
|
||
+ priv_remove_pair_from_triggered_check_queue (agent, pair);
|
||
+ }
|
||
+ return pair;
|
||
+}
|
||
+
|
||
/*
|
||
* Finds the next connectivity check in WAITING state.
|
||
*/
|
||
@@ -107,10 +243,6 @@ static CandidateCheckPair *priv_conn_check_find_next_waiting (GSList *conn_check
|
||
*/
|
||
static gboolean priv_conn_check_initiate (NiceAgent *agent, CandidateCheckPair *pair)
|
||
{
|
||
- /* XXX: from ID-16 onwards, the checks should not be sent
|
||
- * immediately, but be put into the "triggered queue",
|
||
- * see "7.2.1.4 Triggered Checks"
|
||
- */
|
||
g_get_current_time (&pair->next_tick);
|
||
g_time_val_add (&pair->next_tick, agent->timer_ta * 1000);
|
||
pair->state = NICE_CHECK_IN_PROGRESS;
|
||
@@ -142,7 +274,7 @@ static gboolean priv_conn_check_unfreeze_next (NiceAgent *agent)
|
||
*/
|
||
|
||
for (i = agent->streams; i; i = i->next) {
|
||
- Stream *stream = i->data;
|
||
+ NiceStream *stream = i->data;
|
||
guint64 max_frozen_priority = 0;
|
||
|
||
|
||
@@ -185,7 +317,7 @@ static gboolean priv_conn_check_unfreeze_next (NiceAgent *agent)
|
||
*
|
||
* @return TRUE on success, and FALSE if no frozen candidates were found.
|
||
*/
|
||
-static void priv_conn_check_unfreeze_related (NiceAgent *agent, Stream *stream, CandidateCheckPair *ok_check)
|
||
+static void priv_conn_check_unfreeze_related (NiceAgent *agent, NiceStream *stream, CandidateCheckPair *ok_check)
|
||
{
|
||
GSList *i, *j;
|
||
guint unfrozen = 0;
|
||
@@ -212,10 +344,10 @@ static void priv_conn_check_unfreeze_related (NiceAgent *agent, Stream *stream,
|
||
|
||
/* step: perform the step (2) of 'Updating Pair States' */
|
||
stream = agent_find_stream (agent, ok_check->stream_id);
|
||
- if (stream_all_components_ready (stream)) {
|
||
+ if (nice_stream_all_components_ready (stream)) {
|
||
/* step: unfreeze checks from other streams */
|
||
for (i = agent->streams; i ; i = i->next) {
|
||
- Stream *s = i->data;
|
||
+ NiceStream *s = i->data;
|
||
for (j = stream->conncheck_list; j ; j = j->next) {
|
||
CandidateCheckPair *p = j->data;
|
||
|
||
@@ -242,12 +374,12 @@ static void priv_conn_check_unfreeze_related (NiceAgent *agent, Stream *stream,
|
||
}
|
||
|
||
static void
|
||
-candidate_check_pair_fail (Stream *stream, NiceAgent *agent, CandidateCheckPair *p)
|
||
+candidate_check_pair_fail (NiceStream *stream, NiceAgent *agent, CandidateCheckPair *p)
|
||
{
|
||
StunTransactionId id;
|
||
- Component *component;
|
||
+ NiceComponent *component;
|
||
|
||
- component = stream_find_component_by_id (stream, p->component_id);
|
||
+ component = nice_stream_find_component_by_id (stream, p->component_id);
|
||
|
||
p->state = NICE_CHECK_FAILED;
|
||
nice_debug ("Agent %p : pair %p state FAILED", agent, p);
|
||
@@ -269,14 +401,16 @@ candidate_check_pair_fail (Stream *stream, NiceAgent *agent, CandidateCheckPair
|
||
*
|
||
* @return will return FALSE when no more pending timers.
|
||
*/
|
||
-static gboolean priv_conn_check_tick_stream (Stream *stream, NiceAgent *agent, GTimeVal *now)
|
||
+static gboolean priv_conn_check_tick_stream (NiceStream *stream, NiceAgent *agent, GTimeVal *now, gboolean *stun_transmitted)
|
||
{
|
||
gboolean keep_timer_going = FALSE;
|
||
guint s_inprogress = 0, s_succeeded = 0, s_discovered = 0,
|
||
- s_nominated = 0, s_waiting_for_nomination = 0;
|
||
+ s_nominated = 0, s_waiting_for_nomination = 0, s_valid = 0;
|
||
guint frozen = 0, waiting = 0;
|
||
GSList *i, *k;
|
||
|
||
+ priv_print_conn_check_lists (agent, G_STRFUNC, NULL);
|
||
+
|
||
for (i = stream->conncheck_list; i ; i = i->next) {
|
||
CandidateCheckPair *p = i->data;
|
||
|
||
@@ -290,7 +424,13 @@ static gboolean priv_conn_check_tick_stream (Stream *stream, NiceAgent *agent, G
|
||
case STUN_USAGE_TIMER_RETURN_TIMEOUT:
|
||
{
|
||
/* case: error, abort processing */
|
||
+ gchar tmpbuf1[INET6_ADDRSTRLEN], tmpbuf2[INET6_ADDRSTRLEN];
|
||
+ nice_address_to_string (&p->local->addr, tmpbuf1);
|
||
+ nice_address_to_string (&p->remote->addr, tmpbuf2);
|
||
nice_debug ("Agent %p : Retransmissions failed, giving up on connectivity check %p", agent, p);
|
||
+ nice_debug ("Agent %p : Failed pair is [%s]:%u --> [%s]:%u", agent,
|
||
+ tmpbuf1, nice_address_get_port (&p->local->addr),
|
||
+ tmpbuf2, nice_address_get_port (&p->remote->addr));
|
||
candidate_check_pair_fail (stream, agent, p);
|
||
|
||
break;
|
||
@@ -299,8 +439,9 @@ static gboolean priv_conn_check_tick_stream (Stream *stream, NiceAgent *agent, G
|
||
{
|
||
/* case: not ready, so schedule a new timeout */
|
||
unsigned int timeout = stun_timer_remainder (&p->timer);
|
||
- nice_debug ("Agent %p :STUN transaction retransmitted (timeout %dms).",
|
||
- agent, timeout);
|
||
+ nice_debug ("Agent %p :STUN transaction retransmitted on pair %p "
|
||
+ "(timeout %dms, delay=%dms, retrans=%d).",
|
||
+ agent, p, timeout, p->timer.delay, p->timer.retransmissions);
|
||
|
||
agent_socket_send (p->sockptr, &p->remote->addr,
|
||
stun_message_length (&p->stun_message),
|
||
@@ -311,8 +452,8 @@ static gboolean priv_conn_check_tick_stream (Stream *stream, NiceAgent *agent, G
|
||
p->next_tick = *now;
|
||
g_time_val_add (&p->next_tick, timeout * 1000);
|
||
|
||
- keep_timer_going = TRUE;
|
||
- break;
|
||
+ *stun_transmitted = TRUE;
|
||
+ return TRUE;
|
||
}
|
||
case STUN_USAGE_TIMER_RETURN_SUCCESS:
|
||
{
|
||
@@ -342,6 +483,8 @@ static gboolean priv_conn_check_tick_stream (Stream *stream, NiceAgent *agent, G
|
||
++s_succeeded;
|
||
else if (p->state == NICE_CHECK_DISCOVERED)
|
||
++s_discovered;
|
||
+ if (p->valid)
|
||
+ ++s_valid;
|
||
|
||
if ((p->state == NICE_CHECK_SUCCEEDED || p->state == NICE_CHECK_DISCOVERED)
|
||
&& p->nominated)
|
||
@@ -365,7 +508,7 @@ static gboolean priv_conn_check_tick_stream (Stream *stream, NiceAgent *agent, G
|
||
|
||
for (component_item = stream->components; component_item;
|
||
component_item = component_item->next) {
|
||
- Component *component = component_item->data;
|
||
+ NiceComponent *component = component_item->data;
|
||
|
||
for (k = stream->conncheck_list; k ; k = k->next) {
|
||
CandidateCheckPair *p = k->data;
|
||
@@ -375,7 +518,7 @@ static gboolean priv_conn_check_tick_stream (Stream *stream, NiceAgent *agent, G
|
||
p->state == NICE_CHECK_DISCOVERED)) {
|
||
nice_debug ("Agent %p : restarting check %p as the nominated pair.", agent, p);
|
||
p->nominated = TRUE;
|
||
- priv_conn_check_initiate (agent, p);
|
||
+ priv_add_pair_to_triggered_check_queue (agent, p);
|
||
break; /* move to the next component */
|
||
}
|
||
}
|
||
@@ -385,17 +528,28 @@ static gboolean priv_conn_check_tick_stream (Stream *stream, NiceAgent *agent, G
|
||
{
|
||
static int tick_counter = 0;
|
||
if (tick_counter++ % 50 == 0 || keep_timer_going != TRUE)
|
||
- nice_debug ("Agent %p : timer tick #%u: %u frozen, %u in-progress, "
|
||
+ nice_debug ("Agent %p : stream %u: timer tick #%u: %u frozen, %u in-progress, "
|
||
"%u waiting, %u succeeded, %u discovered, %u nominated, "
|
||
- "%u waiting-for-nom.", agent,
|
||
+ "%u waiting-for-nom, %u valid.", agent, stream->id,
|
||
tick_counter, frozen, s_inprogress, waiting, s_succeeded,
|
||
- s_discovered, s_nominated, s_waiting_for_nomination);
|
||
+ s_discovered, s_nominated, s_waiting_for_nomination, s_valid);
|
||
}
|
||
|
||
return keep_timer_going;
|
||
|
||
}
|
||
|
||
+static void
|
||
+conn_check_stop (NiceAgent *agent)
|
||
+{
|
||
+ if (agent->conncheck_timer_source == NULL)
|
||
+ return;
|
||
+
|
||
+ g_source_destroy (agent->conncheck_timer_source);
|
||
+ g_source_unref (agent->conncheck_timer_source);
|
||
+ agent->conncheck_timer_source = NULL;
|
||
+}
|
||
+
|
||
|
||
/*
|
||
* Timer callback that handles initiating and managing connectivity
|
||
@@ -409,15 +563,39 @@ static gboolean priv_conn_check_tick_unlocked (NiceAgent *agent)
|
||
{
|
||
CandidateCheckPair *pair = NULL;
|
||
gboolean keep_timer_going = FALSE;
|
||
+ gboolean res;
|
||
+ /* note: we try to only generate a single stun transaction per timer
|
||
+ * callback, to respect some pacing of STUN transaction, as per
|
||
+ * appendix B.1 of ICE spec.
|
||
+ */
|
||
+ gboolean stun_transmitted = FALSE;
|
||
GSList *i, *j;
|
||
GTimeVal now;
|
||
|
||
/* step: process ongoing STUN transactions */
|
||
g_get_current_time (&now);
|
||
|
||
- /* step: find the highest priority waiting check and send it */
|
||
+ for (j = agent->streams; j; j = j->next) {
|
||
+ NiceStream *stream = j->data;
|
||
+ res = priv_conn_check_tick_stream (stream, agent, &now, &stun_transmitted);
|
||
+ if (res)
|
||
+ keep_timer_going = res;
|
||
+ if (stun_transmitted)
|
||
+ return TRUE;
|
||
+ }
|
||
+
|
||
+ /* step: first initiate a conncheck with a pair from the triggered list */
|
||
+ pair = priv_get_pair_from_triggered_check_queue (agent);
|
||
+
|
||
+ if (pair) {
|
||
+ priv_conn_check_initiate (agent, pair);
|
||
+ return TRUE;
|
||
+ }
|
||
+
|
||
+ /* step: when the triggered list is empty,
|
||
+ * find the highest priority waiting check and send it */
|
||
for (i = agent->streams; i ; i = i->next) {
|
||
- Stream *stream = i->data;
|
||
+ NiceStream *stream = i->data;
|
||
|
||
pair = priv_conn_check_find_next_waiting (stream->conncheck_list);
|
||
if (pair)
|
||
@@ -426,27 +604,37 @@ static gboolean priv_conn_check_tick_unlocked (NiceAgent *agent)
|
||
|
||
if (pair) {
|
||
priv_conn_check_initiate (agent, pair);
|
||
- keep_timer_going = TRUE;
|
||
- } else {
|
||
- keep_timer_going = priv_conn_check_unfreeze_next (agent);
|
||
+ return TRUE;
|
||
}
|
||
|
||
- for (j = agent->streams; j; j = j->next) {
|
||
- Stream *stream = j->data;
|
||
- gboolean res =
|
||
- priv_conn_check_tick_stream (stream, agent, &now);
|
||
- if (res)
|
||
- keep_timer_going = res;
|
||
+ /* step: when there's no pair in the Waiting state,
|
||
+ * unfreeze a new pair and check it
|
||
+ */
|
||
+ res = priv_conn_check_unfreeze_next (agent);
|
||
+
|
||
+ for (i = agent->streams; i ; i = i->next) {
|
||
+ NiceStream *stream = i->data;
|
||
+
|
||
+ pair = priv_conn_check_find_next_waiting (stream->conncheck_list);
|
||
+ if (pair)
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ if (pair) {
|
||
+ priv_print_conn_check_lists (agent, G_STRFUNC,
|
||
+ ", got a pair in Waiting state");
|
||
+ priv_conn_check_initiate (agent, pair);
|
||
+ return TRUE;
|
||
}
|
||
|
||
/* step: stop timer if no work left */
|
||
if (keep_timer_going != TRUE) {
|
||
nice_debug ("Agent %p : %s: stopping conncheck timer", agent, G_STRFUNC);
|
||
for (i = agent->streams; i; i = i->next) {
|
||
- Stream *stream = i->data;
|
||
+ NiceStream *stream = i->data;
|
||
priv_update_check_list_failed_components (agent, stream);
|
||
for (j = stream->components; j; j = j->next) {
|
||
- Component *component = j->data;
|
||
+ NiceComponent *component = j->data;
|
||
priv_update_check_list_state_for_ready (agent, stream, component);
|
||
}
|
||
}
|
||
@@ -454,11 +642,7 @@ static gboolean priv_conn_check_tick_unlocked (NiceAgent *agent)
|
||
/* Stopping the timer so destroy the source.. this will allow
|
||
the timer to be reset if we get a set_remote_candidates after this
|
||
point */
|
||
- if (agent->conncheck_timer_source != NULL) {
|
||
- g_source_destroy (agent->conncheck_timer_source);
|
||
- g_source_unref (agent->conncheck_timer_source);
|
||
- agent->conncheck_timer_source = NULL;
|
||
- }
|
||
+ conn_check_stop (agent);
|
||
|
||
/* XXX: what to signal, is all processing now really done? */
|
||
nice_debug ("Agent %p : changing conncheck state to COMPLETED.", agent);
|
||
@@ -512,7 +696,7 @@ static gboolean priv_conn_keepalive_retransmissions_tick (gpointer pointer)
|
||
{
|
||
/* Time out */
|
||
StunTransactionId id;
|
||
- Component *component;
|
||
+ NiceComponent *component;
|
||
|
||
if (!agent_find_component (pair->keepalive.agent,
|
||
pair->keepalive.stream_id, pair->keepalive.component_id,
|
||
@@ -525,13 +709,12 @@ static gboolean priv_conn_keepalive_retransmissions_tick (gpointer pointer)
|
||
|
||
stun_message_id (&pair->keepalive.stun_message, id);
|
||
stun_agent_forget_transaction (&component->stun_agent, id);
|
||
+ pair->keepalive.stun_message.buffer = NULL;
|
||
|
||
if (pair->keepalive.agent->media_after_tick) {
|
||
nice_debug ("Agent %p : Keepalive conncheck timed out!! "
|
||
"but media was received. Suspecting keepalive lost because of "
|
||
"network bottleneck", pair->keepalive.agent);
|
||
-
|
||
- pair->keepalive.stun_message.buffer = NULL;
|
||
} else {
|
||
nice_debug ("Agent %p : Keepalive conncheck timed out!! "
|
||
"peer probably lost connection", pair->keepalive.agent);
|
||
@@ -561,7 +744,7 @@ static gboolean priv_conn_keepalive_retransmissions_tick (gpointer pointer)
|
||
priv_conn_keepalive_retransmissions_tick, pair);
|
||
break;
|
||
default:
|
||
- /* Nothing to do. */
|
||
+ g_assert_not_reached();
|
||
break;
|
||
}
|
||
|
||
@@ -579,6 +762,7 @@ static guint32 peer_reflexive_candidate_priority (NiceAgent *agent,
|
||
|
||
candidate_priority->transport = local_candidate->transport;
|
||
candidate_priority->component_id = local_candidate->component_id;
|
||
+ candidate_priority->base_addr = local_candidate->addr;
|
||
if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
|
||
priority = nice_candidate_jingle_priority (candidate_priority);
|
||
} else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
|
||
@@ -617,9 +801,9 @@ static gboolean priv_conn_keepalive_tick_unlocked (NiceAgent *agent)
|
||
* (ref ICE sect 10 "Keepalives" ID-19) */
|
||
for (i = agent->streams; i; i = i->next) {
|
||
|
||
- Stream *stream = i->data;
|
||
+ NiceStream *stream = i->data;
|
||
for (j = stream->components; j; j = j->next) {
|
||
- Component *component = j->data;
|
||
+ NiceComponent *component = j->data;
|
||
if (component->selected_pair.local != NULL) {
|
||
CandidatePair *p = &component->selected_pair;
|
||
|
||
@@ -629,7 +813,6 @@ static gboolean priv_conn_keepalive_tick_unlocked (NiceAgent *agent)
|
||
|
||
if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE ||
|
||
agent->keepalive_conncheck) {
|
||
- guint32 priority;
|
||
uint8_t uname[NICE_STREAM_MAX_UNAME];
|
||
size_t uname_len =
|
||
priv_create_username (agent, agent_find_stream (agent, stream->id),
|
||
@@ -639,25 +822,31 @@ static gboolean priv_conn_keepalive_tick_unlocked (NiceAgent *agent)
|
||
size_t password_len = priv_get_password (agent,
|
||
agent_find_stream (agent, stream->id), p->remote, &password);
|
||
|
||
- priority = peer_reflexive_candidate_priority (agent, p->local);
|
||
+ if (p->keepalive.stun_message.buffer != NULL) {
|
||
+ nice_debug ("Agent %p: Keepalive for s%u:c%u still"
|
||
+ " retransmitting, not restarting", agent, stream->id,
|
||
+ component->id);
|
||
+ continue;
|
||
+ }
|
||
|
||
if (nice_debug_is_enabled ()) {
|
||
gchar tmpbuf[INET6_ADDRSTRLEN];
|
||
nice_address_to_string (&p->remote->addr, tmpbuf);
|
||
nice_debug ("Agent %p : Keepalive STUN-CC REQ to '%s:%u', "
|
||
- "socket=%u (c-id:%u), username='%.*s' (%" G_GSIZE_FORMAT "), "
|
||
+ "(c-id:%u), username='%.*s' (%" G_GSIZE_FORMAT "), "
|
||
"password='%.*s' (%" G_GSIZE_FORMAT "), priority=%u.", agent,
|
||
tmpbuf, nice_address_get_port (&p->remote->addr),
|
||
- g_socket_get_fd(((NiceSocket *)p->local->sockptr)->fileno),
|
||
component->id, (int) uname_len, uname, uname_len,
|
||
- (int) password_len, password, password_len, priority);
|
||
+ (int) password_len, password, password_len,
|
||
+ p->prflx_priority);
|
||
}
|
||
if (uname_len > 0) {
|
||
buf_len = stun_usage_ice_conncheck_create (&component->stun_agent,
|
||
&p->keepalive.stun_message, p->keepalive.stun_buffer,
|
||
sizeof(p->keepalive.stun_buffer),
|
||
uname, uname_len, password, password_len,
|
||
- agent->controlling_mode, agent->controlling_mode, priority,
|
||
+ agent->controlling_mode, agent->controlling_mode,
|
||
+ p->prflx_priority,
|
||
agent->tie_breaker,
|
||
NULL,
|
||
agent_to_ice_compatibility (agent));
|
||
@@ -709,9 +898,9 @@ static gboolean priv_conn_keepalive_tick_unlocked (NiceAgent *agent)
|
||
/* case 2: connectivity establishment ongoing
|
||
* (ref ICE sect 4.1.1.4 "Keeping Candidates Alive" ID-19) */
|
||
for (i = agent->streams; i; i = i->next) {
|
||
- Stream *stream = i->data;
|
||
+ NiceStream *stream = i->data;
|
||
for (j = stream->components; j; j = j->next) {
|
||
- Component *component = j->data;
|
||
+ NiceComponent *component = j->data;
|
||
if (component->state < NICE_COMPONENT_STATE_READY &&
|
||
agent->stun_server_ip) {
|
||
NiceAddress stun_server;
|
||
@@ -723,12 +912,7 @@ static gboolean priv_conn_keepalive_tick_unlocked (NiceAgent *agent)
|
||
|
||
nice_address_set_port (&stun_server, agent->stun_server_port);
|
||
|
||
- /* FIXME: This will cause the stun response to arrive on the socket
|
||
- * but the stun agent will not be able to parse it due to an invalid
|
||
- * stun message since RFC3489 will not be compatible, and the response
|
||
- * will be forwarded to the application as user data */
|
||
- stun_agent_init (&stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
|
||
- STUN_COMPATIBILITY_RFC3489, 0);
|
||
+ nice_agent_init_stun_agent (agent, &stun_agent);
|
||
|
||
buffer_len = stun_usage_bind_create (&stun_agent,
|
||
&stun_message, stun_buffer, sizeof(stun_buffer));
|
||
@@ -937,23 +1121,14 @@ static gboolean priv_turn_allocate_refresh_tick (gpointer pointer)
|
||
|
||
/*
|
||
* Initiates the next pending connectivity check.
|
||
- *
|
||
- * @return TRUE if a pending check was scheduled
|
||
*/
|
||
-gboolean conn_check_schedule_next (NiceAgent *agent)
|
||
+void conn_check_schedule_next (NiceAgent *agent)
|
||
{
|
||
- gboolean res = priv_conn_check_unfreeze_next (agent);
|
||
- nice_debug ("Agent %p : priv_conn_check_unfreeze_next returned %d", agent, res);
|
||
-
|
||
if (agent->discovery_unsched_items > 0)
|
||
nice_debug ("Agent %p : WARN: starting conn checks before local candidate gathering is finished.", agent);
|
||
|
||
- /* step: call once imediately */
|
||
- res = priv_conn_check_tick_unlocked (agent);
|
||
- nice_debug ("Agent %p : priv_conn_check_tick_unlocked returned %d", agent, res);
|
||
-
|
||
/* step: schedule timer if not running yet */
|
||
- if (res && agent->conncheck_timer_source == NULL) {
|
||
+ if (agent->conncheck_timer_source == NULL) {
|
||
agent_timeout_add_with_context (agent, &agent->conncheck_timer_source,
|
||
"Connectivity check schedule", agent->timer_ta,
|
||
priv_conn_check_tick, agent);
|
||
@@ -965,9 +1140,6 @@ gboolean conn_check_schedule_next (NiceAgent *agent)
|
||
"Connectivity keepalive timeout", NICE_AGENT_TIMER_TR_DEFAULT,
|
||
priv_conn_keepalive_tick, agent);
|
||
}
|
||
-
|
||
- nice_debug ("Agent %p : conn_check_schedule_next returning %d", agent, res);
|
||
- return res;
|
||
}
|
||
|
||
/*
|
||
@@ -995,7 +1167,7 @@ gint conn_check_compare (const CandidateCheckPair *a, const CandidateCheckPair *
|
||
* @param component pointer to component object to which 'pair'has been added
|
||
* @param pair newly added connectivity check
|
||
*/
|
||
-static void priv_preprocess_conn_check_pending_data (NiceAgent *agent, Stream *stream, Component *component, CandidateCheckPair *pair)
|
||
+static void priv_preprocess_conn_check_pending_data (NiceAgent *agent, NiceStream *stream, NiceComponent *component, CandidateCheckPair *pair)
|
||
{
|
||
GSList *i;
|
||
for (i = component->incoming_checks; i; i = i->next) {
|
||
@@ -1004,7 +1176,7 @@ static void priv_preprocess_conn_check_pending_data (NiceAgent *agent, Stream *s
|
||
icheck->local_socket == pair->sockptr) {
|
||
nice_debug ("Agent %p : Updating check %p with stored early-icheck %p, %p/%u/%u (agent/stream/component).", agent, pair, icheck, agent, stream->id, component->id);
|
||
if (icheck->use_candidate)
|
||
- priv_mark_pair_nominated (agent, stream, component, pair->remote);
|
||
+ priv_mark_pair_nominated (agent, stream, component, pair->local, pair->remote);
|
||
priv_schedule_triggered_check (agent, stream, component, icheck->local_socket, pair->remote, icheck->use_candidate);
|
||
}
|
||
}
|
||
@@ -1039,15 +1211,13 @@ static GSList *prune_cancelled_conn_check (GSList *conncheck_list)
|
||
* reaches us. The special case is documented in sect 7.2
|
||
* if ICE spec (ID-19).
|
||
*/
|
||
-void conn_check_remote_candidates_set(NiceAgent *agent)
|
||
+void conn_check_remote_candidates_set(NiceAgent *agent, NiceStream *stream, NiceComponent *component)
|
||
{
|
||
- GSList *i, *j, *k, *l, *m, *n;
|
||
+ GSList *j, *k, *l, *m, *n;
|
||
|
||
- for (i = agent->streams; i ; i = i->next) {
|
||
- Stream *stream = i->data;
|
||
- for (j = stream->conncheck_list; j ; j = j->next) {
|
||
- CandidateCheckPair *pair = j->data;
|
||
- Component *component = stream_find_component_by_id (stream, pair->component_id);
|
||
+ for (j = stream->conncheck_list; j ; j = j->next) {
|
||
+ CandidateCheckPair *pair = j->data;
|
||
+ if (pair->component_id == component->id) {
|
||
gboolean match = FALSE;
|
||
|
||
/* performn delayed processing of spec steps section 7.2.1.4,
|
||
@@ -1148,24 +1318,24 @@ void conn_check_remote_candidates_set(NiceAgent *agent)
|
||
conn_check_add_for_candidate (agent, stream->id, component, candidate);
|
||
|
||
if (icheck->use_candidate)
|
||
- priv_mark_pair_nominated (agent, stream, component, candidate);
|
||
+ priv_mark_pair_nominated (agent, stream, component, local_candidate, candidate);
|
||
priv_schedule_triggered_check (agent, stream, component, icheck->local_socket, candidate, icheck->use_candidate);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
-
|
||
- /* Once we process the pending checks, we should free them to avoid
|
||
- * reprocessing them again if a dribble-mode set_remote_candidates
|
||
- * is called */
|
||
- g_slist_free_full (component->incoming_checks,
|
||
- (GDestroyNotify) incoming_check_free);
|
||
- component->incoming_checks = NULL;
|
||
}
|
||
-
|
||
- stream->conncheck_list =
|
||
- prune_cancelled_conn_check (stream->conncheck_list);
|
||
}
|
||
+
|
||
+ /* Once we process the pending checks, we should free them to avoid
|
||
+ * reprocessing them again if a dribble-mode set_remote_candidates
|
||
+ * is called */
|
||
+ g_slist_free_full (component->incoming_checks,
|
||
+ (GDestroyNotify) incoming_check_free);
|
||
+ component->incoming_checks = NULL;
|
||
+
|
||
+ stream->conncheck_list =
|
||
+ prune_cancelled_conn_check (stream->conncheck_list);
|
||
}
|
||
|
||
/*
|
||
@@ -1204,20 +1374,23 @@ static void priv_limit_conn_check_list_size (GSList *conncheck_list, guint upper
|
||
* and has higher priority than the currently selected pair. See
|
||
* ICE sect 11.1.1. "Procedures for Full Implementations" (ID-19).
|
||
*/
|
||
-static gboolean priv_update_selected_pair (NiceAgent *agent, Component *component, CandidateCheckPair *pair)
|
||
+static gboolean priv_update_selected_pair (NiceAgent *agent, NiceComponent *component, CandidateCheckPair *pair)
|
||
{
|
||
- CandidatePair cpair;
|
||
+ CandidatePair cpair = { 0, };
|
||
|
||
g_assert (component);
|
||
g_assert (pair);
|
||
- if (pair->priority > component->selected_pair.priority &&
|
||
- component_find_pair (component, agent, pair->local->foundation,
|
||
- pair->remote->foundation, &cpair)) {
|
||
+ if (pair->priority > component->selected_pair.priority) {
|
||
nice_debug ("Agent %p : changing SELECTED PAIR for component %u: %s:%s "
|
||
"(prio:%" G_GUINT64_FORMAT ").", agent, component->id,
|
||
pair->local->foundation, pair->remote->foundation, pair->priority);
|
||
|
||
- component_update_selected_pair (component, &cpair);
|
||
+ cpair.local = pair->local;
|
||
+ cpair.remote = pair->remote;
|
||
+ cpair.priority = pair->priority;
|
||
+ /* cpair.keepalive is not used by nice_component_update_selected_pair() */
|
||
+
|
||
+ nice_component_update_selected_pair (component, &cpair);
|
||
|
||
priv_conn_keepalive_tick_unlocked (agent);
|
||
|
||
@@ -1239,7 +1412,7 @@ static gboolean priv_update_selected_pair (NiceAgent *agent, Component *componen
|
||
*
|
||
* Sends a component state changesignal via 'agent'.
|
||
*/
|
||
-static void priv_update_check_list_failed_components (NiceAgent *agent, Stream *stream)
|
||
+static void priv_update_check_list_failed_components (NiceAgent *agent, NiceStream *stream)
|
||
{
|
||
GSList *i;
|
||
/* note: emitting a signal might cause the client
|
||
@@ -1261,7 +1434,7 @@ static void priv_update_check_list_failed_components (NiceAgent *agent, Stream *
|
||
|
||
/* note: iterate the conncheck list for each component separately */
|
||
for (c = 0; c < components; c++) {
|
||
- Component *comp = NULL;
|
||
+ NiceComponent *comp = NULL;
|
||
if (!agent_find_component (agent, stream->id, c+1, NULL, &comp))
|
||
continue;
|
||
|
||
@@ -1299,10 +1472,10 @@ static void priv_update_check_list_failed_components (NiceAgent *agent, Stream *
|
||
*
|
||
* Sends a component state changesignal via 'agent'.
|
||
*/
|
||
-static void priv_update_check_list_state_for_ready (NiceAgent *agent, Stream *stream, Component *component)
|
||
+static void priv_update_check_list_state_for_ready (NiceAgent *agent, NiceStream *stream, NiceComponent *component)
|
||
{
|
||
GSList *i;
|
||
- guint succeeded = 0, nominated = 0;
|
||
+ guint valid = 0, nominated = 0;
|
||
|
||
g_assert (component);
|
||
|
||
@@ -1310,26 +1483,36 @@ static void priv_update_check_list_state_for_ready (NiceAgent *agent, Stream *st
|
||
for (i = stream->conncheck_list; i; i = i->next) {
|
||
CandidateCheckPair *p = i->data;
|
||
if (p->component_id == component->id) {
|
||
- if (p->state == NICE_CHECK_SUCCEEDED ||
|
||
- p->state == NICE_CHECK_DISCOVERED) {
|
||
- ++succeeded;
|
||
+ if (p->valid) {
|
||
+ ++valid;
|
||
if (p->nominated == TRUE) {
|
||
++nominated;
|
||
+ priv_update_selected_pair (agent, component, p);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
- if (nominated > 0) {
|
||
+ if (valid > 0) {
|
||
/* Only go to READY if no checks are left in progress. If there are
|
||
* any that are kept, then this function will be called again when the
|
||
* conncheck tick timer finishes them all */
|
||
if (priv_prune_pending_checks (stream, component->id) == 0) {
|
||
+ /* Continue through the states to give client code a nice
|
||
+ * logical progression. See http://phabricator.freedesktop.org/D218 for
|
||
+ * discussion. */
|
||
+ if (component->state < NICE_COMPONENT_STATE_CONNECTING ||
|
||
+ component->state == NICE_COMPONENT_STATE_FAILED)
|
||
+ agent_signal_component_state_change (agent, stream->id, component->id,
|
||
+ NICE_COMPONENT_STATE_CONNECTING);
|
||
+ if (component->state < NICE_COMPONENT_STATE_CONNECTED)
|
||
+ agent_signal_component_state_change (agent, stream->id, component->id,
|
||
+ NICE_COMPONENT_STATE_CONNECTED);
|
||
agent_signal_component_state_change (agent, stream->id,
|
||
component->id, NICE_COMPONENT_STATE_READY);
|
||
}
|
||
}
|
||
- nice_debug ("Agent %p : conn.check list status: %u nominated, %u succeeded, c-id %u.", agent, nominated, succeeded, component->id);
|
||
+ nice_debug ("Agent %p : conn.check list status: %u nominated, %u valid, c-id %u.", agent, nominated, valid, component->id);
|
||
}
|
||
|
||
/*
|
||
@@ -1337,7 +1520,7 @@ static void priv_update_check_list_state_for_ready (NiceAgent *agent, Stream *st
|
||
* described by 'component' and 'remotecand' is nominated
|
||
* for use.
|
||
*/
|
||
-static void priv_mark_pair_nominated (NiceAgent *agent, Stream *stream, Component *component, NiceCandidate *remotecand)
|
||
+static void priv_mark_pair_nominated (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceCandidate *localcand, NiceCandidate *remotecand)
|
||
{
|
||
GSList *i;
|
||
|
||
@@ -1346,27 +1529,66 @@ static void priv_mark_pair_nominated (NiceAgent *agent, Stream *stream, Componen
|
||
/* step: search for at least one nominated pair */
|
||
for (i = stream->conncheck_list; i; i = i->next) {
|
||
CandidateCheckPair *pair = i->data;
|
||
- /* XXX: hmm, how to figure out to which local candidate the
|
||
- * check was sent to? let's mark all matching pairs
|
||
- * as nominated instead */
|
||
- if (pair->remote == remotecand) {
|
||
+ if (pair->local == localcand && pair->remote == remotecand) {
|
||
nice_debug ("Agent %p : marking pair %p (%s) as nominated", agent, pair, pair->foundation);
|
||
pair->nominated = TRUE;
|
||
- if (pair->state == NICE_CHECK_SUCCEEDED ||
|
||
- pair->state == NICE_CHECK_DISCOVERED)
|
||
+ if (pair->valid) {
|
||
priv_update_selected_pair (agent, component, pair);
|
||
+ /* Do not step down to CONNECTED if we're already at state READY*/
|
||
+ if (component->state != NICE_COMPONENT_STATE_READY) {
|
||
+ /* step: notify the client of a new component state (must be done
|
||
+ * before the possible check list state update step */
|
||
+ agent_signal_component_state_change (agent,
|
||
+ stream->id, component->id, NICE_COMPONENT_STATE_CONNECTED);
|
||
+ }
|
||
+
|
||
+ }
|
||
priv_update_check_list_state_for_ready (agent, stream, component);
|
||
}
|
||
}
|
||
}
|
||
|
||
+guint32
|
||
+ensure_unique_priority (NiceComponent *component, guint32 priority)
|
||
+{
|
||
+ GSList *item;
|
||
+
|
||
+ again:
|
||
+ if (priority == 0)
|
||
+ priority--;
|
||
+
|
||
+ for (item = component->local_candidates; item; item = item->next) {
|
||
+ NiceCandidate *cand = item->data;
|
||
+
|
||
+ if (cand->priority == priority) {
|
||
+ priority--;
|
||
+ goto again;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ for (item = component->stream->conncheck_list; item; item = item->next) {
|
||
+ CandidateCheckPair *p = item->data;
|
||
+
|
||
+ if (p->component_id == component->id &&
|
||
+ p->prflx_priority == priority) {
|
||
+ priority--;
|
||
+ goto again;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return priority;
|
||
+}
|
||
+
|
||
+
|
||
/*
|
||
* Creates a new connectivity check pair and adds it to
|
||
* the agent's list of checks.
|
||
*/
|
||
-static void priv_add_new_check_pair (NiceAgent *agent, guint stream_id, Component *component, NiceCandidate *local, NiceCandidate *remote, NiceCheckState initial_state, gboolean use_candidate)
|
||
+static CandidateCheckPair *priv_add_new_check_pair (NiceAgent *agent,
|
||
+ guint stream_id, NiceComponent *component, NiceCandidate *local,
|
||
+ NiceCandidate *remote, NiceCheckState initial_state, gboolean use_candidate)
|
||
{
|
||
- Stream *stream;
|
||
+ NiceStream *stream;
|
||
CandidateCheckPair *pair;
|
||
|
||
g_assert (local != NULL);
|
||
@@ -1389,8 +1611,19 @@ static void priv_add_new_check_pair (NiceAgent *agent, guint stream_id, Componen
|
||
pair->priority = agent_candidate_pair_priority (agent, local, remote);
|
||
pair->state = initial_state;
|
||
nice_debug ("Agent %p : creating new pair %p state %d", agent, pair, initial_state);
|
||
+ {
|
||
+ gchar tmpbuf1[INET6_ADDRSTRLEN];
|
||
+ gchar tmpbuf2[INET6_ADDRSTRLEN];
|
||
+ nice_address_to_string (&pair->local->addr, tmpbuf1);
|
||
+ nice_address_to_string (&pair->remote->addr, tmpbuf2);
|
||
+ nice_debug ("Agent %p : new pair %p : [%s]:%u --> [%s]:%u", agent, pair,
|
||
+ tmpbuf1, nice_address_get_port (&pair->local->addr),
|
||
+ tmpbuf2, nice_address_get_port (&pair->remote->addr));
|
||
+ }
|
||
pair->nominated = use_candidate;
|
||
pair->controlling = agent->controlling_mode;
|
||
+ pair->prflx_priority = ensure_unique_priority (component,
|
||
+ peer_reflexive_candidate_priority (agent, local));
|
||
|
||
stream->conncheck_list = g_slist_insert_sorted (stream->conncheck_list, pair,
|
||
(GCompareFunc)conn_check_compare);
|
||
@@ -1402,6 +1635,8 @@ static void priv_add_new_check_pair (NiceAgent *agent, guint stream_id, Componen
|
||
if (agent->compatibility == NICE_COMPATIBILITY_RFC5245) {
|
||
priv_limit_conn_check_list_size (stream->conncheck_list, agent->max_conn_checks);
|
||
}
|
||
+
|
||
+ return pair;
|
||
}
|
||
|
||
NiceCandidateTransport
|
||
@@ -1422,13 +1657,16 @@ conn_check_match_transport (NiceCandidateTransport transport)
|
||
}
|
||
}
|
||
|
||
-static void priv_conn_check_add_for_candidate_pair_matched (NiceAgent *agent,
|
||
- guint stream_id, Component *component, NiceCandidate *local,
|
||
- NiceCandidate *remote, NiceCheckState initial_state)
|
||
+static CandidateCheckPair *priv_conn_check_add_for_candidate_pair_matched (
|
||
+ NiceAgent *agent, guint stream_id, NiceComponent *component,
|
||
+ NiceCandidate *local, NiceCandidate *remote, NiceCheckState initial_state)
|
||
{
|
||
- nice_debug ("Agent %p, Adding check pair between %s and %s", agent,
|
||
- local->foundation, remote->foundation);
|
||
- priv_add_new_check_pair (agent, stream_id, component, local, remote,
|
||
+ CandidateCheckPair *pair;
|
||
+
|
||
+ nice_debug ("Agent %p : Adding check pair between %s and %s for s%d/c%d",
|
||
+ agent, local->foundation, remote->foundation,
|
||
+ stream_id, component->id);
|
||
+ pair = priv_add_new_check_pair (agent, stream_id, component, local, remote,
|
||
initial_state, FALSE);
|
||
if (component->state == NICE_COMPONENT_STATE_CONNECTED ||
|
||
component->state == NICE_COMPONENT_STATE_READY) {
|
||
@@ -1442,10 +1680,12 @@ static void priv_conn_check_add_for_candidate_pair_matched (NiceAgent *agent,
|
||
component->id,
|
||
NICE_COMPONENT_STATE_CONNECTING);
|
||
}
|
||
+
|
||
+ return pair;
|
||
}
|
||
|
||
gboolean conn_check_add_for_candidate_pair (NiceAgent *agent,
|
||
- guint stream_id, Component *component, NiceCandidate *local,
|
||
+ guint stream_id, NiceComponent *component, NiceCandidate *local,
|
||
NiceCandidate *remote)
|
||
{
|
||
gboolean ret = FALSE;
|
||
@@ -1491,7 +1731,7 @@ gboolean conn_check_add_for_candidate_pair (NiceAgent *agent,
|
||
*
|
||
* @return number of checks added, negative on fatal errors
|
||
*/
|
||
-int conn_check_add_for_candidate (NiceAgent *agent, guint stream_id, Component *component, NiceCandidate *remote)
|
||
+int conn_check_add_for_candidate (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *remote)
|
||
{
|
||
GSList *i;
|
||
int added = 0;
|
||
@@ -1500,8 +1740,11 @@ int conn_check_add_for_candidate (NiceAgent *agent, guint stream_id, Component *
|
||
g_assert (remote != NULL);
|
||
|
||
for (i = component->local_candidates; i ; i = i->next) {
|
||
-
|
||
NiceCandidate *local = i->data;
|
||
+
|
||
+ if (agent->force_relay && local->type != NICE_CANDIDATE_TYPE_RELAYED)
|
||
+ continue;
|
||
+
|
||
ret = conn_check_add_for_candidate_pair (agent, stream_id, component, local, remote);
|
||
|
||
if (ret) {
|
||
@@ -1522,7 +1765,7 @@ int conn_check_add_for_candidate (NiceAgent *agent, guint stream_id, Component *
|
||
*
|
||
* @return number of checks added, negative on fatal errors
|
||
*/
|
||
-int conn_check_add_for_local_candidate (NiceAgent *agent, guint stream_id, Component *component, NiceCandidate *local)
|
||
+int conn_check_add_for_local_candidate (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *local)
|
||
{
|
||
GSList *i;
|
||
int added = 0;
|
||
@@ -1551,22 +1794,13 @@ static void conn_check_free_item (gpointer data)
|
||
{
|
||
CandidateCheckPair *pair = data;
|
||
|
||
+ if (pair->agent)
|
||
+ priv_remove_pair_from_triggered_check_queue (pair->agent, pair);
|
||
pair->stun_message.buffer = NULL;
|
||
pair->stun_message.buffer_len = 0;
|
||
g_slice_free (CandidateCheckPair, pair);
|
||
}
|
||
|
||
-static void
|
||
-conn_check_stop (NiceAgent *agent)
|
||
-{
|
||
- if (agent->conncheck_timer_source == NULL)
|
||
- return;
|
||
-
|
||
- g_source_destroy (agent->conncheck_timer_source);
|
||
- g_source_unref (agent->conncheck_timer_source);
|
||
- agent->conncheck_timer_source = NULL;
|
||
-}
|
||
-
|
||
/*
|
||
* Frees all resources of all connectivity checks.
|
||
*/
|
||
@@ -1574,7 +1808,7 @@ void conn_check_free (NiceAgent *agent)
|
||
{
|
||
GSList *i;
|
||
for (i = agent->streams; i; i = i->next) {
|
||
- Stream *stream = i->data;
|
||
+ NiceStream *stream = i->data;
|
||
|
||
if (stream->conncheck_list) {
|
||
nice_debug ("Agent %p, freeing conncheck_list of stream %p", agent,
|
||
@@ -1593,7 +1827,7 @@ void conn_check_free (NiceAgent *agent)
|
||
*
|
||
* @return TRUE on success, FALSE on a fatal error
|
||
*/
|
||
-void conn_check_prune_stream (NiceAgent *agent, Stream *stream)
|
||
+void conn_check_prune_stream (NiceAgent *agent, NiceStream *stream)
|
||
{
|
||
GSList *i;
|
||
gboolean keep_going = FALSE;
|
||
@@ -1606,7 +1840,7 @@ void conn_check_prune_stream (NiceAgent *agent, Stream *stream)
|
||
}
|
||
|
||
for (i = agent->streams; i; i = i->next) {
|
||
- Stream *s = i->data;
|
||
+ NiceStream *s = i->data;
|
||
if (s->conncheck_list) {
|
||
keep_going = TRUE;
|
||
break;
|
||
@@ -1717,7 +1951,7 @@ size_t priv_gen_username (NiceAgent *agent, guint component_id,
|
||
* NULL) is ever written to the 'dest'.
|
||
*/
|
||
static
|
||
-size_t priv_create_username (NiceAgent *agent, Stream *stream,
|
||
+size_t priv_create_username (NiceAgent *agent, NiceStream *stream,
|
||
guint component_id, NiceCandidate *remote, NiceCandidate *local,
|
||
uint8_t *dest, guint dest_len, gboolean inbound)
|
||
{
|
||
@@ -1760,7 +1994,7 @@ size_t priv_create_username (NiceAgent *agent, Stream *stream,
|
||
* check.
|
||
*/
|
||
static
|
||
-size_t priv_get_password (NiceAgent *agent, Stream *stream,
|
||
+size_t priv_get_password (NiceAgent *agent, NiceStream *stream,
|
||
NiceCandidate *remote, uint8_t **password)
|
||
{
|
||
if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE)
|
||
@@ -1781,26 +2015,30 @@ size_t priv_get_password (NiceAgent *agent, Stream *stream,
|
||
|
||
/* Implement the computation specific in RFC 5245 section 16 */
|
||
|
||
-static unsigned int priv_compute_conncheck_timer (NiceAgent *agent,
|
||
- Stream *stream)
|
||
+static unsigned int priv_compute_conncheck_timer (NiceAgent *agent)
|
||
{
|
||
- GSList *item;
|
||
+ GSList *item1, *item2;
|
||
guint waiting_and_in_progress = 0;
|
||
unsigned int rto = 0;
|
||
|
||
- for (item = stream->conncheck_list; item; item = item->next) {
|
||
- CandidateCheckPair *pair = item->data;
|
||
|
||
- if (pair->state == NICE_CHECK_IN_PROGRESS ||
|
||
- pair->state == NICE_CHECK_WAITING)
|
||
- waiting_and_in_progress++;
|
||
+ for (item1 = agent->streams; item1; item1 = item1->next) {
|
||
+ NiceStream *stream = item1->data;;
|
||
+ for (item2 = stream->conncheck_list; item2; item2 = item2->next) {
|
||
+ CandidateCheckPair *pair = item2->data;
|
||
+
|
||
+ if (pair->state == NICE_CHECK_IN_PROGRESS ||
|
||
+ pair->state == NICE_CHECK_WAITING)
|
||
+ waiting_and_in_progress++;
|
||
+ }
|
||
}
|
||
|
||
- /* FIXME: This should also be multiple by "N", which I believe is the
|
||
- * number of Streams currently in the conncheck state. */
|
||
rto = agent->timer_ta * waiting_and_in_progress;
|
||
|
||
/* We assume non-reliable streams are RTP, so we use 100 as the max */
|
||
+ nice_debug ("Agent %p : timer set to %dms (waiting+in_progress=%d)",
|
||
+ agent, agent->reliable ? MAX (rto, 500) : MAX (rto, 100),
|
||
+ waiting_and_in_progress);
|
||
if (agent->reliable)
|
||
return MAX (rto, 500);
|
||
else
|
||
@@ -1822,11 +2060,10 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
|
||
* - ICE-CONTROLLED/ICE-CONTROLLING (for role conflicts)
|
||
* - USE-CANDIDATE (if sent by the controlling agent)
|
||
*/
|
||
- guint32 priority;
|
||
|
||
uint8_t uname[NICE_STREAM_MAX_UNAME];
|
||
- Stream *stream;
|
||
- Component *component;
|
||
+ NiceStream *stream;
|
||
+ NiceComponent *component;
|
||
gsize uname_len;
|
||
uint8_t *password = NULL;
|
||
gsize password_len;
|
||
@@ -1844,8 +2081,6 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
|
||
pair->remote, pair->local, uname, sizeof (uname), FALSE);
|
||
password_len = priv_get_password (agent, stream, pair->remote, &password);
|
||
|
||
- priority = peer_reflexive_candidate_priority (agent, pair->local);
|
||
-
|
||
if (password != NULL &&
|
||
(agent->compatibility == NICE_COMPATIBILITY_MSN ||
|
||
agent->compatibility == NICE_COMPATIBILITY_OC2007)) {
|
||
@@ -1853,20 +2088,21 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
|
||
}
|
||
|
||
if (nice_debug_is_enabled ()) {
|
||
- gchar tmpbuf[INET6_ADDRSTRLEN];
|
||
- nice_address_to_string (&pair->remote->addr, tmpbuf);
|
||
- nice_debug ("Agent %p : STUN-CC REQ to '%s:%u', socket=%u, "
|
||
+ gchar tmpbuf1[INET6_ADDRSTRLEN];
|
||
+ gchar tmpbuf2[INET6_ADDRSTRLEN];
|
||
+ nice_address_to_string (&pair->local->addr, tmpbuf1);
|
||
+ nice_address_to_string (&pair->remote->addr, tmpbuf2);
|
||
+ nice_debug ("Agent %p : STUN-CC REQ [%s]:%u --> [%s]:%u, socket=%u, "
|
||
"pair=%s (c-id:%u), tie=%llu, username='%.*s' (%" G_GSIZE_FORMAT "), "
|
||
- "password='%.*s' (%" G_GSIZE_FORMAT "), priority=%u.", agent,
|
||
- tmpbuf,
|
||
- nice_address_get_port (&pair->remote->addr),
|
||
+ "password='%.*s' (%" G_GSIZE_FORMAT "), prio=%u, cont=%d.", agent,
|
||
+ tmpbuf1, nice_address_get_port (&pair->local->addr),
|
||
+ tmpbuf2, nice_address_get_port (&pair->remote->addr),
|
||
pair->sockptr->fileno ? g_socket_get_fd(pair->sockptr->fileno) : -1,
|
||
pair->foundation, pair->component_id,
|
||
(unsigned long long)agent->tie_breaker,
|
||
(int) uname_len, uname, uname_len,
|
||
(int) password_len, password, password_len,
|
||
- priority);
|
||
-
|
||
+ pair->prflx_priority, controlling);
|
||
}
|
||
|
||
if (cand_use)
|
||
@@ -1876,7 +2112,7 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
|
||
buffer_len = stun_usage_ice_conncheck_create (&component->stun_agent,
|
||
&pair->stun_message, pair->stun_buffer, sizeof(pair->stun_buffer),
|
||
uname, uname_len, password, password_len,
|
||
- cand_use, controlling, priority,
|
||
+ cand_use, controlling, pair->prflx_priority,
|
||
agent->tie_breaker,
|
||
pair->local->foundation,
|
||
agent_to_ice_compatibility (agent));
|
||
@@ -1894,7 +2130,7 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
|
||
stun_timer_start_reliable(&pair->timer, STUN_TIMER_DEFAULT_RELIABLE_TIMEOUT);
|
||
} else {
|
||
stun_timer_start (&pair->timer,
|
||
- priv_compute_conncheck_timer (agent, stream),
|
||
+ priv_compute_conncheck_timer (agent),
|
||
STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS);
|
||
}
|
||
|
||
@@ -1902,9 +2138,10 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
|
||
* by connecting to the peer. The new socket is stored in the candidate
|
||
* check pair, until we discover a new local peer reflexive */
|
||
if (pair->sockptr->fileno == NULL &&
|
||
+ pair->sockptr->type != NICE_SOCKET_TYPE_UDP_TURN &&
|
||
pair->local->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE) {
|
||
- Stream *stream2 = NULL;
|
||
- Component *component2 = NULL;
|
||
+ NiceStream *stream2 = NULL;
|
||
+ NiceComponent *component2 = NULL;
|
||
NiceSocket *new_socket;
|
||
|
||
if (agent_find_component (agent, pair->stream_id, pair->component_id,
|
||
@@ -1914,7 +2151,13 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
|
||
if (new_socket) {
|
||
pair->sockptr = new_socket;
|
||
_priv_set_socket_tos (agent, pair->sockptr, stream2->tos);
|
||
- component_attach_socket (component2, new_socket);
|
||
+
|
||
+ if (agent->reliable) {
|
||
+ nice_socket_set_writable_callback (pair->sockptr,
|
||
+ _tcp_sock_is_writable, component2);
|
||
+ }
|
||
+
|
||
+ nice_component_attach_socket (component2, new_socket);
|
||
}
|
||
}
|
||
}
|
||
@@ -1948,7 +2191,7 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
|
||
*
|
||
* @see priv_update_check_list_state_failed_components()
|
||
*/
|
||
-static guint priv_prune_pending_checks (Stream *stream, guint component_id)
|
||
+static guint priv_prune_pending_checks (NiceStream *stream, guint component_id)
|
||
{
|
||
GSList *i;
|
||
guint64 highest_nominated_priority = 0;
|
||
@@ -1959,10 +2202,8 @@ static guint priv_prune_pending_checks (Stream *stream, guint component_id)
|
||
|
||
for (i = stream->conncheck_list; i; i = i->next) {
|
||
CandidateCheckPair *p = i->data;
|
||
- if (p->component_id == component_id &&
|
||
- (p->state == NICE_CHECK_SUCCEEDED ||
|
||
- p->state == NICE_CHECK_DISCOVERED) &&
|
||
- p->nominated == TRUE){
|
||
+ if (p->component_id == component_id && p->valid == TRUE &&
|
||
+ p->nominated == TRUE) {
|
||
if (p->priority > highest_nominated_priority) {
|
||
highest_nominated_priority = p->priority;
|
||
}
|
||
@@ -2015,7 +2256,7 @@ static guint priv_prune_pending_checks (Stream *stream, guint component_id)
|
||
* @param remote_cand remote candidate from which the inbound check was sent
|
||
* @param use_candidate whether the original check had USE-CANDIDATE attribute set
|
||
*/
|
||
-static gboolean priv_schedule_triggered_check (NiceAgent *agent, Stream *stream, Component *component, NiceSocket *local_socket, NiceCandidate *remote_cand, gboolean use_candidate)
|
||
+static gboolean priv_schedule_triggered_check (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceSocket *local_socket, NiceCandidate *remote_cand, gboolean use_candidate)
|
||
{
|
||
GSList *i;
|
||
NiceCandidate *local = NULL;
|
||
@@ -2038,7 +2279,7 @@ static gboolean priv_schedule_triggered_check (NiceAgent *agent, Stream *stream,
|
||
|
||
if (p->state == NICE_CHECK_WAITING ||
|
||
p->state == NICE_CHECK_FROZEN)
|
||
- priv_conn_check_initiate (agent, p);
|
||
+ priv_add_pair_to_triggered_check_queue (agent, p);
|
||
else if (p->state == NICE_CHECK_IN_PROGRESS) {
|
||
/* XXX: according to ICE 7.2.1.4 "Triggered Checks" (ID-19),
|
||
* we should cancel the existing one, instead we reset our timer, so
|
||
@@ -2049,7 +2290,7 @@ static gboolean priv_schedule_triggered_check (NiceAgent *agent, Stream *stream,
|
||
p->timer_restarted ? "no" : "yes");
|
||
if (!nice_socket_is_reliable (p->sockptr) && !p->timer_restarted) {
|
||
stun_timer_start (&p->timer,
|
||
- priv_compute_conncheck_timer (agent, stream),
|
||
+ priv_compute_conncheck_timer (agent),
|
||
STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS);
|
||
p->timer_restarted = TRUE;
|
||
}
|
||
@@ -2059,23 +2300,36 @@ static gboolean priv_schedule_triggered_check (NiceAgent *agent, Stream *stream,
|
||
nice_debug ("Agent %p : Skipping triggered check, already completed..", agent);
|
||
/* note: this is a bit unsure corner-case -- let's do the
|
||
same state update as for processing responses to our own checks */
|
||
+ /* note: this update is required by the dribble test, to
|
||
+ * ensure the transition ready -> connected -> ready, because
|
||
+ * an incoming stun request generates a discovered peer reflexive,
|
||
+ * that causes the ready -> connected transition.
|
||
+ */
|
||
priv_update_check_list_state_for_ready (agent, stream, component);
|
||
|
||
- /* note: to take care of the controlling-controlling case in
|
||
- * aggressive nomination mode, send a new triggered
|
||
- * check to nominate the pair */
|
||
+ /* note: this new check is required by the new-dribble test,
|
||
+ * when early icheck on the peer controlled agent causes an
|
||
+ * incoming stun request to an already succeeded (and
|
||
+ * nominated) pair on the controlling agent. If the
|
||
+ * controlling agent doesn't retrigger a check with
|
||
+ * USE-CANDIDATE=1, the peer agent has no way to nominate it.
|
||
+ *
|
||
+ * This behavior differs from ICE spec 7.2.1.4
|
||
+ */
|
||
if ((agent->compatibility == NICE_COMPATIBILITY_RFC5245 ||
|
||
agent->compatibility == NICE_COMPATIBILITY_WLM2009 ||
|
||
agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
|
||
- agent->controlling_mode)
|
||
- priv_conn_check_initiate (agent, p);
|
||
+ agent->controlling_mode) {
|
||
+ priv_add_pair_to_triggered_check_queue (agent, p);
|
||
+ conn_check_schedule_next(agent);
|
||
+ }
|
||
} else if (p->state == NICE_CHECK_FAILED) {
|
||
/* 7.2.1.4 Triggered Checks
|
||
* If the state of the pair is Failed, it is changed to Waiting
|
||
and the agent MUST create a new connectivity check for that
|
||
pair (representing a new STUN Binding request transaction), by
|
||
enqueueing the pair in the triggered check queue. */
|
||
- priv_conn_check_initiate (agent, p);
|
||
+ priv_add_pair_to_triggered_check_queue (agent, p);
|
||
}
|
||
|
||
/* note: the spec says the we SHOULD retransmit in-progress
|
||
@@ -2121,7 +2375,7 @@ static gboolean priv_schedule_triggered_check (NiceAgent *agent, Stream *stream,
|
||
*
|
||
* @pre (rcand == NULL || nice_address_equal(rcand->addr, toaddr) == TRUE)
|
||
*/
|
||
-static void priv_reply_to_conn_check (NiceAgent *agent, Stream *stream, Component *component, NiceCandidate *rcand, const NiceAddress *toaddr, NiceSocket *sockptr, size_t rbuf_len, uint8_t *rbuf, gboolean use_candidate)
|
||
+static void priv_reply_to_conn_check (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceCandidate *lcand, NiceCandidate *rcand, const NiceAddress *toaddr, NiceSocket *sockptr, size_t rbuf_len, uint8_t *rbuf, gboolean use_candidate)
|
||
{
|
||
g_assert (rcand == NULL || nice_address_equal(&rcand->addr, toaddr) == TRUE);
|
||
|
||
@@ -2144,7 +2398,7 @@ static void priv_reply_to_conn_check (NiceAgent *agent, Stream *stream, Componen
|
||
priv_schedule_triggered_check (agent, stream, component, sockptr, rcand, use_candidate);
|
||
|
||
if (use_candidate)
|
||
- priv_mark_pair_nominated (agent, stream, component, rcand);
|
||
+ priv_mark_pair_nominated (agent, stream, component, lcand, rcand);
|
||
}
|
||
}
|
||
|
||
@@ -2156,7 +2410,7 @@ static void priv_reply_to_conn_check (NiceAgent *agent, Stream *stream, Componen
|
||
*
|
||
* @return non-zero on error, zero on success
|
||
*/
|
||
-static int priv_store_pending_check (NiceAgent *agent, Component *component,
|
||
+static int priv_store_pending_check (NiceAgent *agent, NiceComponent *component,
|
||
const NiceAddress *from, NiceSocket *sockptr, uint8_t *username,
|
||
uint16_t username_len, uint32_t priority, gboolean use_candidate)
|
||
{
|
||
@@ -2190,19 +2444,28 @@ static int priv_store_pending_check (NiceAgent *agent, Component *component,
|
||
*
|
||
* @return created pair, or NULL on fatal (memory allocation) errors
|
||
*/
|
||
-static CandidateCheckPair *priv_add_peer_reflexive_pair (NiceAgent *agent, guint stream_id, guint component_id, NiceCandidate *local_cand, CandidateCheckPair *parent_pair)
|
||
+static CandidateCheckPair *priv_add_peer_reflexive_pair (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *local_cand, CandidateCheckPair *parent_pair)
|
||
{
|
||
CandidateCheckPair *pair = g_slice_new0 (CandidateCheckPair);
|
||
- Stream *stream = agent_find_stream (agent, stream_id);
|
||
+ NiceStream *stream = agent_find_stream (agent, stream_id);
|
||
|
||
pair->agent = agent;
|
||
pair->stream_id = stream_id;
|
||
- pair->component_id = component_id;;
|
||
+ pair->component_id = component->id;;
|
||
pair->local = local_cand;
|
||
pair->remote = parent_pair->remote;
|
||
pair->sockptr = local_cand->sockptr;
|
||
pair->state = NICE_CHECK_DISCOVERED;
|
||
- nice_debug ("Agent %p : pair %p state DISCOVERED", agent, pair);
|
||
+ nice_debug ("Agent %p : new pair %p state DISCOVERED", agent, pair);
|
||
+ {
|
||
+ gchar tmpbuf1[INET6_ADDRSTRLEN];
|
||
+ gchar tmpbuf2[INET6_ADDRSTRLEN];
|
||
+ nice_address_to_string (&pair->local->addr, tmpbuf1);
|
||
+ nice_address_to_string (&pair->remote->addr, tmpbuf2);
|
||
+ nice_debug ("Agent %p : new pair %p : [%s]:%u --> [%s]:%u", agent, pair,
|
||
+ tmpbuf1, nice_address_get_port (&pair->local->addr),
|
||
+ tmpbuf2, nice_address_get_port (&pair->remote->addr));
|
||
+ }
|
||
g_snprintf (pair->foundation, NICE_CANDIDATE_PAIR_MAX_FOUNDATION, "%s:%s",
|
||
local_cand->foundation, parent_pair->remote->foundation);
|
||
if (agent->controlling_mode == TRUE)
|
||
@@ -2213,6 +2476,8 @@ static CandidateCheckPair *priv_add_peer_reflexive_pair (NiceAgent *agent, guint
|
||
pair->local->priority);
|
||
pair->nominated = FALSE;
|
||
pair->controlling = agent->controlling_mode;
|
||
+ pair->prflx_priority = ensure_unique_priority (component,
|
||
+ peer_reflexive_candidate_priority (agent, local_cand));
|
||
nice_debug ("Agent %p : added a new peer-discovered pair with foundation of '%s'.", agent, pair->foundation);
|
||
|
||
stream->conncheck_list = g_slist_insert_sorted (stream->conncheck_list, pair,
|
||
@@ -2230,11 +2495,13 @@ static void priv_recalculate_pair_priorities (NiceAgent *agent)
|
||
GSList *i, *j;
|
||
|
||
for (i = agent->streams; i; i = i->next) {
|
||
- Stream *stream = i->data;
|
||
+ NiceStream *stream = i->data;
|
||
for (j = stream->conncheck_list; j; j = j->next) {
|
||
CandidateCheckPair *p = j->data;
|
||
p->priority = agent_candidate_pair_priority (agent, p->local, p->remote);
|
||
}
|
||
+ stream->conncheck_list = g_slist_sort (stream->conncheck_list,
|
||
+ (GCompareFunc)conn_check_compare);
|
||
}
|
||
}
|
||
|
||
@@ -2269,21 +2536,21 @@ static void priv_check_for_role_conflict (NiceAgent *agent, gboolean control)
|
||
* @param socketptr socket used to send the reply
|
||
* @param mapped_sockaddr mapped address in the response
|
||
*
|
||
- * @return pointer to a new pair if one was created, otherwise NULL
|
||
+ * @return pointer to a candidate pair, found in conncheck list or newly created
|
||
*/
|
||
-static CandidateCheckPair *priv_process_response_check_for_peer_reflexive(NiceAgent *agent, Stream *stream, Component *component, CandidateCheckPair *p, NiceSocket *sockptr, struct sockaddr *mapped_sockaddr, NiceCandidate *local_candidate, NiceCandidate *remote_candidate)
|
||
+static CandidateCheckPair *priv_process_response_check_for_reflexive(NiceAgent *agent, NiceStream *stream, NiceComponent *component, CandidateCheckPair *p, NiceSocket *sockptr, struct sockaddr *mapped_sockaddr, NiceCandidate *local_candidate, NiceCandidate *remote_candidate)
|
||
{
|
||
CandidateCheckPair *new_pair = NULL;
|
||
NiceAddress mapped;
|
||
GSList *i, *j;
|
||
- gboolean local_cand_matches = FALSE;
|
||
+ NiceCandidate *local_cand = NULL;
|
||
|
||
nice_address_set_from_sockaddr (&mapped, mapped_sockaddr);
|
||
|
||
for (j = component->local_candidates; j; j = j->next) {
|
||
NiceCandidate *cand = j->data;
|
||
if (nice_address_equal (&mapped, &cand->addr)) {
|
||
- local_cand_matches = TRUE;
|
||
+ local_cand = cand;
|
||
|
||
/* We always need to select the peer-reflexive Candidate Pair in the case
|
||
* of a TCP-ACTIVE local candidate, so we find it even if an incoming
|
||
@@ -2300,31 +2567,38 @@ static CandidateCheckPair *priv_process_response_check_for_peer_reflexive(NiceAg
|
||
}
|
||
}
|
||
|
||
- if (local_cand_matches == TRUE) {
|
||
- /* note: this is same as "adding to VALID LIST" in the spec
|
||
- text */
|
||
+ if (new_pair) {
|
||
p->state = NICE_CHECK_SUCCEEDED;
|
||
nice_debug ("Agent %p : conncheck %p SUCCEEDED.", agent, p);
|
||
priv_conn_check_unfreeze_related (agent, stream, p);
|
||
}
|
||
else {
|
||
- NiceCandidate *cand =
|
||
- discovery_add_peer_reflexive_candidate (agent,
|
||
- stream->id,
|
||
- component->id,
|
||
- &mapped,
|
||
- sockptr,
|
||
- local_candidate,
|
||
- remote_candidate);
|
||
- p->state = NICE_CHECK_FAILED;
|
||
- nice_debug ("Agent %p : pair %p state FAILED", agent, p);
|
||
+ if (!local_cand) {
|
||
+ if (!agent->force_relay)
|
||
+ local_cand = discovery_add_peer_reflexive_candidate (agent,
|
||
+ stream->id,
|
||
+ component->id,
|
||
+ &mapped,
|
||
+ sockptr,
|
||
+ local_candidate,
|
||
+ remote_candidate);
|
||
+ p->state = NICE_CHECK_FAILED;
|
||
+ nice_debug ("Agent %p : pair %p state FAILED", agent, p);
|
||
+ }
|
||
|
||
/* step: add a new discovered pair (see RFC 5245 7.1.3.2.2
|
||
"Constructing a Valid Pair") */
|
||
- new_pair = priv_add_peer_reflexive_pair (agent, stream->id, component->id, cand, p);
|
||
+ if (local_cand)
|
||
+ new_pair = priv_add_peer_reflexive_pair (agent, stream->id, component,
|
||
+ local_cand, p);
|
||
nice_debug ("Agent %p : conncheck %p FAILED, %p DISCOVERED.", agent, p, new_pair);
|
||
}
|
||
|
||
+ /* note: this is same as "adding to VALID LIST" in the spec
|
||
+ text */
|
||
+ if (new_pair)
|
||
+ new_pair->valid = TRUE;
|
||
+
|
||
return new_pair;
|
||
}
|
||
|
||
@@ -2335,7 +2609,7 @@ static CandidateCheckPair *priv_process_response_check_for_peer_reflexive(NiceAg
|
||
*
|
||
* @return TRUE if a matching transaction is found
|
||
*/
|
||
-static gboolean priv_map_reply_to_conn_check_request (NiceAgent *agent, Stream *stream, Component *component, NiceSocket *sockptr, const NiceAddress *from, NiceCandidate *local_candidate, NiceCandidate *remote_candidate, StunMessage *resp)
|
||
+static gboolean priv_map_reply_to_conn_check_request (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceSocket *sockptr, const NiceAddress *from, NiceCandidate *local_candidate, NiceCandidate *remote_candidate, StunMessage *resp)
|
||
{
|
||
union {
|
||
struct sockaddr_storage storage;
|
||
@@ -2404,11 +2678,13 @@ static gboolean priv_map_reply_to_conn_check_request (NiceAgent *agent, Stream *
|
||
/* note: this is same as "adding to VALID LIST" in the spec
|
||
text */
|
||
p->state = NICE_CHECK_SUCCEEDED;
|
||
+ p->valid = TRUE;
|
||
+ g_assert_not_reached ();
|
||
nice_debug ("Agent %p : Mapped address not found."
|
||
" conncheck %p SUCCEEDED.", agent, p);
|
||
priv_conn_check_unfreeze_related (agent, stream, p);
|
||
} else {
|
||
- ok_pair = priv_process_response_check_for_peer_reflexive (agent,
|
||
+ ok_pair = priv_process_response_check_for_reflexive (agent,
|
||
stream, component, p, sockptr, &sockaddr.addr,
|
||
local_candidate, remote_candidate);
|
||
}
|
||
@@ -2431,6 +2707,8 @@ static gboolean priv_map_reply_to_conn_check_request (NiceAgent *agent, Stream *
|
||
}
|
||
}
|
||
|
||
+ priv_print_conn_check_lists (agent, G_STRFUNC, NULL);
|
||
+
|
||
/* step: update pair states (ICE 7.1.2.2.3 "Updating pair
|
||
states" and 8.1.2 "Updating States", ID-19) */
|
||
priv_update_check_list_state_for_ready (agent, stream, component);
|
||
@@ -2447,6 +2725,7 @@ static gboolean priv_map_reply_to_conn_check_request (NiceAgent *agent, Stream *
|
||
p->stun_message.buffer = NULL;
|
||
p->stun_message.buffer_len = 0;
|
||
p->state = NICE_CHECK_WAITING;
|
||
+ priv_add_pair_to_triggered_check_queue (agent, p);
|
||
nice_debug ("Agent %p : pair %p state WAITING", agent, p);
|
||
trans_found = TRUE;
|
||
} else {
|
||
@@ -2516,25 +2795,27 @@ static gboolean priv_map_reply_to_discovery_request (NiceAgent *agent, StunMessa
|
||
d->pending = FALSE;
|
||
} else if (res == STUN_USAGE_BIND_RETURN_SUCCESS) {
|
||
/* case: successful binding discovery, create a new local candidate */
|
||
- NiceAddress niceaddr;
|
||
- nice_address_set_from_sockaddr (&niceaddr, &sockaddr.addr);
|
||
-
|
||
- discovery_add_server_reflexive_candidate (
|
||
- d->agent,
|
||
- d->stream->id,
|
||
- d->component->id,
|
||
- &niceaddr,
|
||
- NICE_CANDIDATE_TRANSPORT_UDP,
|
||
- d->nicesock,
|
||
- FALSE);
|
||
- if (d->agent->use_ice_tcp)
|
||
- discovery_discover_tcp_server_reflexive_candidates (
|
||
+
|
||
+ if (!agent->force_relay) {
|
||
+ NiceAddress niceaddr;
|
||
+
|
||
+ nice_address_set_from_sockaddr (&niceaddr, &sockaddr.addr);
|
||
+ discovery_add_server_reflexive_candidate (
|
||
d->agent,
|
||
d->stream->id,
|
||
d->component->id,
|
||
&niceaddr,
|
||
- d->nicesock);
|
||
-
|
||
+ NICE_CANDIDATE_TRANSPORT_UDP,
|
||
+ d->nicesock,
|
||
+ FALSE);
|
||
+ if (d->agent->use_ice_tcp)
|
||
+ discovery_discover_tcp_server_reflexive_candidates (
|
||
+ d->agent,
|
||
+ d->stream->id,
|
||
+ d->component->id,
|
||
+ &niceaddr,
|
||
+ d->nicesock);
|
||
+ }
|
||
d->stun_message.buffer = NULL;
|
||
d->stun_message.buffer_len = 0;
|
||
d->done = TRUE;
|
||
@@ -2667,7 +2948,8 @@ static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *
|
||
* on a TCP connection, which cannot be used for server-reflexive
|
||
* discovery of candidates.
|
||
*/
|
||
- if (d->turn->type == NICE_RELAY_TYPE_TURN_UDP) {
|
||
+ if (d->turn->type == NICE_RELAY_TYPE_TURN_UDP &&
|
||
+ !agent->force_relay) {
|
||
discovery_add_server_reflexive_candidate (
|
||
d->agent,
|
||
d->stream->id,
|
||
@@ -2729,6 +3011,9 @@ static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *
|
||
}
|
||
|
||
if (relay_cand) {
|
||
+ if (d->stun_resp_msg.buffer)
|
||
+ nice_udp_turn_socket_cache_realm_nonce (relay_cand->sockptr,
|
||
+ &d->stun_resp_msg);
|
||
if (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
|
||
agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
|
||
/* These data are needed on TURN socket when sending requests,
|
||
@@ -2744,6 +3029,9 @@ static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *
|
||
} else {
|
||
priv_add_new_turn_refresh (d, relay_cand, lifetime);
|
||
}
|
||
+
|
||
+ /* In case a new candidate has been added */
|
||
+ conn_check_schedule_next (agent);
|
||
}
|
||
|
||
d->stun_message.buffer = NULL;
|
||
@@ -2889,7 +3177,7 @@ static gboolean priv_map_reply_to_relay_refresh (NiceAgent *agent, StunMessage *
|
||
|
||
|
||
static gboolean priv_map_reply_to_keepalive_conncheck (NiceAgent *agent,
|
||
- Component *component, StunMessage *resp)
|
||
+ NiceComponent *component, StunMessage *resp)
|
||
{
|
||
StunTransactionId conncheck_id;
|
||
StunTransactionId response_id;
|
||
@@ -2917,8 +3205,8 @@ static gboolean priv_map_reply_to_keepalive_conncheck (NiceAgent *agent,
|
||
|
||
typedef struct {
|
||
NiceAgent *agent;
|
||
- Stream *stream;
|
||
- Component *component;
|
||
+ NiceStream *stream;
|
||
+ NiceComponent *component;
|
||
uint8_t *password;
|
||
} conncheck_validater_data;
|
||
|
||
@@ -2957,7 +3245,7 @@ static bool conncheck_stun_validater (StunAgent *agent,
|
||
if (ufrag == NULL)
|
||
continue;
|
||
|
||
- stun_debug ("Comparing username/ufrag of len %d and %zu, equal=%d",
|
||
+ stun_debug ("Comparing username/ufrag of len %d and %" G_GSIZE_FORMAT ", equal=%d",
|
||
username_len, ufrag_len, username_len >= ufrag_len ?
|
||
memcmp (username, ufrag, ufrag_len) : 0);
|
||
stun_debug_bytes (" username: ", username, username_len);
|
||
@@ -3014,8 +3302,8 @@ static bool conncheck_stun_validater (StunAgent *agent,
|
||
*
|
||
* @return XXX (what FALSE means exactly?)
|
||
*/
|
||
-gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream,
|
||
- Component *component, NiceSocket *nicesock, const NiceAddress *from,
|
||
+gboolean conn_check_handle_inbound_stun (NiceAgent *agent, NiceStream *stream,
|
||
+ NiceComponent *component, NiceSocket *nicesock, const NiceAddress *from,
|
||
gchar *buf, guint len)
|
||
{
|
||
union {
|
||
@@ -3080,9 +3368,11 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream,
|
||
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->candidate->sockptr,
|
||
- nicesock);
|
||
+
|
||
+ nice_debug_verbose ("Comparing %p to %p, %p to %p and %p and %p to %p",
|
||
+ r->stream, stream, r->component, component, r->nicesock,
|
||
+ r->candidate->sockptr, nicesock);
|
||
+
|
||
if (r->stream == stream && r->component == component &&
|
||
(r->nicesock == nicesock || r->candidate->sockptr == nicesock)) {
|
||
valid = stun_agent_validate (&r->stun_agent, &req,
|
||
@@ -3294,16 +3584,22 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream,
|
||
remote_candidate2 ? remote_candidate2 : remote_candidate);
|
||
if(remote_candidate) {
|
||
if (local_candidate &&
|
||
- local_candidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE)
|
||
- priv_conn_check_add_for_candidate_pair_matched (agent,
|
||
- stream->id, component, local_candidate, remote_candidate, NICE_CHECK_DISCOVERED);
|
||
- else
|
||
+ local_candidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE) {
|
||
+ CandidateCheckPair *pair;
|
||
+
|
||
+ pair = priv_conn_check_add_for_candidate_pair_matched (agent,
|
||
+ stream->id, component, local_candidate, remote_candidate,
|
||
+ NICE_CHECK_DISCOVERED);
|
||
+ if (pair) {
|
||
+ pair->valid = TRUE;
|
||
+ }
|
||
+ } else
|
||
conn_check_add_for_candidate (agent, stream->id, component, remote_candidate);
|
||
}
|
||
}
|
||
|
||
- priv_reply_to_conn_check (agent, stream, component, remote_candidate,
|
||
- from, nicesock, rbuf_len, rbuf, use_candidate);
|
||
+ priv_reply_to_conn_check (agent, stream, component, local_candidate,
|
||
+ remote_candidate, from, nicesock, rbuf_len, rbuf, use_candidate);
|
||
|
||
if (component->remote_candidates == NULL) {
|
||
/* case: We've got a valid binding request to a local candidate
|
||
@@ -3360,7 +3656,7 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream,
|
||
/* Remove all pointers to the given @sock from the connection checking process.
|
||
* These are entirely NiceCandidates pointed to from various places. */
|
||
void
|
||
-conn_check_prune_socket (NiceAgent *agent, Stream *stream, Component *component,
|
||
+conn_check_prune_socket (NiceAgent *agent, NiceStream *stream, NiceComponent *component,
|
||
NiceSocket *sock)
|
||
{
|
||
GSList *l;
|
||
@@ -3375,14 +3671,20 @@ conn_check_prune_socket (NiceAgent *agent, Stream *stream, Component *component,
|
||
}
|
||
|
||
/* Prune from the candidate check pairs. */
|
||
- for (l = stream->conncheck_list; l != NULL; l = l->next) {
|
||
+ for (l = stream->conncheck_list; l != NULL;) {
|
||
CandidateCheckPair *p = l->data;
|
||
+ GSList *next = l->next;
|
||
|
||
if ((p->local != NULL && p->local->sockptr == sock) ||
|
||
- (p->remote != NULL && p->remote->sockptr == sock)) {
|
||
+ (p->remote != NULL && p->remote->sockptr == sock) ||
|
||
+ (p->sockptr == sock)) {
|
||
nice_debug ("Agent %p : Retransmissions failed, giving up on "
|
||
"connectivity check %p", agent, p);
|
||
candidate_check_pair_fail (stream, agent, p);
|
||
+ conn_check_free_item (p);
|
||
+ stream->conncheck_list = g_slist_delete_link (stream->conncheck_list, l);
|
||
}
|
||
+
|
||
+ l = next;
|
||
}
|
||
}
|
||
diff --git a/agent/conncheck.h b/agent/conncheck.h
|
||
index e6c2c62..431c606 100644
|
||
--- a/agent/conncheck.h
|
||
+++ b/agent/conncheck.h
|
||
@@ -87,26 +87,30 @@ struct _CandidateCheckPair
|
||
gboolean nominated;
|
||
gboolean controlling;
|
||
gboolean timer_restarted;
|
||
+ gboolean valid;
|
||
guint64 priority;
|
||
+ guint32 prflx_priority;
|
||
GTimeVal next_tick; /* next tick timestamp */
|
||
StunTimer timer;
|
||
uint8_t stun_buffer[STUN_MAX_MESSAGE_SIZE_IPV6];
|
||
StunMessage stun_message;
|
||
};
|
||
|
||
-int conn_check_add_for_candidate (NiceAgent *agent, guint stream_id, Component *component, NiceCandidate *remote);
|
||
-int conn_check_add_for_local_candidate (NiceAgent *agent, guint stream_id, Component *component, NiceCandidate *local);
|
||
-gboolean conn_check_add_for_candidate_pair (NiceAgent *agent, guint stream_id, Component *component, NiceCandidate *local, NiceCandidate *remote);
|
||
+int conn_check_add_for_candidate (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *remote);
|
||
+int conn_check_add_for_local_candidate (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *local);
|
||
+gboolean conn_check_add_for_candidate_pair (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *local, NiceCandidate *remote);
|
||
void conn_check_free (NiceAgent *agent);
|
||
-gboolean conn_check_schedule_next (NiceAgent *agent);
|
||
+void conn_check_schedule_next (NiceAgent *agent);
|
||
int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair);
|
||
-void conn_check_prune_stream (NiceAgent *agent, Stream *stream);
|
||
-gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream, Component *component, NiceSocket *udp_socket, const NiceAddress *from, gchar *buf, guint len);
|
||
+void conn_check_prune_stream (NiceAgent *agent, NiceStream *stream);
|
||
+gboolean conn_check_handle_inbound_stun (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceSocket *udp_socket, const NiceAddress *from, gchar *buf, guint len);
|
||
gint conn_check_compare (const CandidateCheckPair *a, const CandidateCheckPair *b);
|
||
-void conn_check_remote_candidates_set(NiceAgent *agent);
|
||
+void conn_check_remote_candidates_set(NiceAgent *agent, NiceStream *stream, NiceComponent *component);
|
||
NiceCandidateTransport conn_check_match_transport (NiceCandidateTransport transport);
|
||
void
|
||
-conn_check_prune_socket (NiceAgent *agent, Stream *stream, Component *component,
|
||
+conn_check_prune_socket (NiceAgent *agent, NiceStream *stream, NiceComponent *component,
|
||
NiceSocket *sock);
|
||
|
||
+guint32 ensure_unique_priority (NiceComponent *component, guint32 priority);
|
||
+
|
||
#endif /*_NICE_CONNCHECK_H */
|
||
diff --git a/agent/debug.c b/agent/debug.c
|
||
index 6e69f9b..e1a298c 100644
|
||
--- a/agent/debug.c
|
||
+++ b/agent/debug.c
|
||
@@ -48,17 +48,29 @@
|
||
#include "agent-priv.h"
|
||
|
||
static int debug_enabled = 0;
|
||
+static int debug_verbose_enabled = 0;
|
||
|
||
#define NICE_DEBUG_STUN 1
|
||
#define NICE_DEBUG_NICE 2
|
||
#define NICE_DEBUG_PSEUDOTCP 4
|
||
#define NICE_DEBUG_PSEUDOTCP_VERBOSE 8
|
||
+#define NICE_DEBUG_NICE_VERBOSE 16
|
||
|
||
static const GDebugKey keys[] = {
|
||
{ (gchar *)"stun", NICE_DEBUG_STUN },
|
||
{ (gchar *)"nice", NICE_DEBUG_NICE },
|
||
{ (gchar *)"pseudotcp", NICE_DEBUG_PSEUDOTCP },
|
||
{ (gchar *)"pseudotcp-verbose", NICE_DEBUG_PSEUDOTCP_VERBOSE },
|
||
+ { (gchar *)"nice-verbose", NICE_DEBUG_NICE_VERBOSE },
|
||
+ { NULL, 0},
|
||
+};
|
||
+
|
||
+static const GDebugKey gkeys[] = {
|
||
+ { (gchar *)"libnice-stun", NICE_DEBUG_STUN },
|
||
+ { (gchar *)"libnice", NICE_DEBUG_NICE },
|
||
+ { (gchar *)"libnice-pseudotcp", NICE_DEBUG_PSEUDOTCP },
|
||
+ { (gchar *)"libnice-pseudotcp-verbose", NICE_DEBUG_PSEUDOTCP_VERBOSE },
|
||
+ { (gchar *)"libnice-verbose", NICE_DEBUG_NICE_VERBOSE },
|
||
{ NULL, 0},
|
||
};
|
||
|
||
@@ -86,18 +98,30 @@ void nice_debug_init (void)
|
||
|
||
if (flags_string)
|
||
flags = g_parse_debug_string (flags_string, keys, 4);
|
||
+ if (gflags_string)
|
||
+ flags |= g_parse_debug_string (gflags_string, gkeys, 4);
|
||
if (gflags_string && strstr (gflags_string, "libnice-pseudotcp-verbose"))
|
||
flags |= NICE_DEBUG_PSEUDOTCP_VERBOSE;
|
||
+ if (gflags_string && strstr (gflags_string, "libnice-nice-verbose")) {
|
||
+ flags |= NICE_DEBUG_NICE_VERBOSE;
|
||
+ }
|
||
|
||
stun_set_debug_handler (stun_handler);
|
||
- nice_debug_enable (TRUE);
|
||
+ debug_enabled = !!(flags & NICE_DEBUG_NICE);
|
||
+ if (flags & NICE_DEBUG_STUN)
|
||
+ stun_debug_enable ();
|
||
+ else
|
||
+ stun_debug_disable ();
|
||
+
|
||
+ if (flags & NICE_DEBUG_NICE_VERBOSE)
|
||
+ debug_verbose_enabled = TRUE;
|
||
|
||
/* Set verbose before normal so that if we use 'all', then only
|
||
normal debug is enabled, we'd need to set pseudotcp-verbose without the
|
||
pseudotcp flag in order to actually enable verbose pseudotcp */
|
||
if (flags & NICE_DEBUG_PSEUDOTCP_VERBOSE)
|
||
pseudo_tcp_set_debug_level (PSEUDO_TCP_DEBUG_VERBOSE);
|
||
- else
|
||
+ else if (flags & NICE_DEBUG_PSEUDOTCP)
|
||
pseudo_tcp_set_debug_level (PSEUDO_TCP_DEBUG_NORMAL);
|
||
}
|
||
}
|
||
@@ -107,6 +131,10 @@ gboolean nice_debug_is_enabled (void)
|
||
{
|
||
return debug_enabled;
|
||
}
|
||
+gboolean nice_debug_is_verbose (void)
|
||
+{
|
||
+ return debug_verbose_enabled;
|
||
+}
|
||
#else
|
||
/* Defined in agent-priv.h. */
|
||
#endif
|
||
@@ -136,6 +164,15 @@ void nice_debug (const char *fmt, ...)
|
||
va_end (ap);
|
||
}
|
||
}
|
||
+void nice_debug_verbose (const char *fmt, ...)
|
||
+{
|
||
+ va_list ap;
|
||
+ if (debug_verbose_enabled) {
|
||
+ va_start (ap, fmt);
|
||
+ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, fmt, ap);
|
||
+ va_end (ap);
|
||
+ }
|
||
+}
|
||
#else
|
||
/* Defined in agent-priv.h. */
|
||
#endif
|
||
diff --git a/agent/discovery.c b/agent/discovery.c
|
||
index f3a702d..7a890a0 100644
|
||
--- a/agent/discovery.c
|
||
+++ b/agent/discovery.c
|
||
@@ -305,7 +305,7 @@ void refresh_cancel (CandidateRefresh *refresh)
|
||
* defined in ICE spec section 4.1.3 "Eliminating Redundant
|
||
* Candidates" (ID-19).
|
||
*/
|
||
-static gboolean priv_add_local_candidate_pruned (NiceAgent *agent, guint stream_id, Component *component, NiceCandidate *candidate)
|
||
+static gboolean priv_add_local_candidate_pruned (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *candidate)
|
||
{
|
||
GSList *i;
|
||
|
||
@@ -329,7 +329,7 @@ static gboolean priv_add_local_candidate_pruned (NiceAgent *agent, guint stream_
|
||
return TRUE;
|
||
}
|
||
|
||
-static guint priv_highest_remote_foundation (Component *component)
|
||
+static guint priv_highest_remote_foundation (NiceComponent *component)
|
||
{
|
||
GSList *i;
|
||
guint highest = 1;
|
||
@@ -382,9 +382,9 @@ static void priv_assign_foundation (NiceAgent *agent, NiceCandidate *candidate)
|
||
GSList *i, *j, *k;
|
||
|
||
for (i = agent->streams; i; i = i->next) {
|
||
- Stream *stream = i->data;
|
||
+ NiceStream *stream = i->data;
|
||
for (j = stream->components; j; j = j->next) {
|
||
- Component *component = j->data;
|
||
+ NiceComponent *component = j->data;
|
||
for (k = component->local_candidates; k; k = k->next) {
|
||
NiceCandidate *n = k->data;
|
||
|
||
@@ -393,7 +393,6 @@ static void priv_assign_foundation (NiceAgent *agent, NiceCandidate *candidate)
|
||
|
||
if (candidate->type == n->type &&
|
||
candidate->transport == n->transport &&
|
||
- candidate->stream_id == n->stream_id &&
|
||
nice_address_equal_no_port (&candidate->base_addr, &n->base_addr) &&
|
||
(candidate->type != NICE_CANDIDATE_TYPE_RELAYED ||
|
||
priv_compare_turn_servers (candidate->turn, n->turn)) &&
|
||
@@ -427,12 +426,12 @@ static void priv_assign_remote_foundation (NiceAgent *agent, NiceCandidate *cand
|
||
{
|
||
GSList *i, *j, *k;
|
||
guint next_remote_id;
|
||
- Component *component = NULL;
|
||
+ NiceComponent *component = NULL;
|
||
|
||
for (i = agent->streams; i; i = i->next) {
|
||
- Stream *stream = i->data;
|
||
+ NiceStream *stream = i->data;
|
||
for (j = stream->components; j; j = j->next) {
|
||
- Component *c = j->data;
|
||
+ NiceComponent *c = j->data;
|
||
|
||
if (c->id == candidate->component_id)
|
||
component = c;
|
||
@@ -523,8 +522,8 @@ HostCandidateResult discovery_add_local_host_candidate (
|
||
NiceCandidate **outcandidate)
|
||
{
|
||
NiceCandidate *candidate;
|
||
- Component *component;
|
||
- Stream *stream;
|
||
+ NiceComponent *component;
|
||
+ NiceStream *stream;
|
||
NiceSocket *nicesock = NULL;
|
||
HostCandidateResult res = HOST_CANDIDATE_FAILED;
|
||
|
||
@@ -550,6 +549,8 @@ HostCandidateResult discovery_add_local_host_candidate (
|
||
agent->reliable, FALSE);
|
||
}
|
||
|
||
+ candidate->priority = ensure_unique_priority (component,
|
||
+ candidate->priority);
|
||
priv_generate_candidate_credentials (agent, candidate);
|
||
priv_assign_foundation (agent, candidate);
|
||
|
||
@@ -580,7 +581,7 @@ HostCandidateResult discovery_add_local_host_candidate (
|
||
}
|
||
|
||
_priv_set_socket_tos (agent, nicesock, stream->tos);
|
||
- component_attach_socket (component, nicesock);
|
||
+ nice_component_attach_socket (component, nicesock);
|
||
|
||
*outcandidate = candidate;
|
||
|
||
@@ -610,8 +611,8 @@ discovery_add_server_reflexive_candidate (
|
||
gboolean nat_assisted)
|
||
{
|
||
NiceCandidate *candidate;
|
||
- Component *component;
|
||
- Stream *stream;
|
||
+ NiceComponent *component;
|
||
+ NiceStream *stream;
|
||
gboolean result = FALSE;
|
||
|
||
if (!agent_find_component (agent, stream_id, component_id, &stream, &component))
|
||
@@ -623,6 +624,10 @@ discovery_add_server_reflexive_candidate (
|
||
candidate->component_id = component_id;
|
||
candidate->addr = *address;
|
||
|
||
+ /* step: link to the base candidate+socket */
|
||
+ candidate->sockptr = base_socket;
|
||
+ candidate->base_addr = base_socket->addr;
|
||
+
|
||
if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
|
||
candidate->priority = nice_candidate_jingle_priority (candidate);
|
||
} else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
|
||
@@ -636,10 +641,8 @@ discovery_add_server_reflexive_candidate (
|
||
agent->reliable, nat_assisted);
|
||
}
|
||
|
||
- /* step: link to the base candidate+socket */
|
||
- candidate->sockptr = base_socket;
|
||
- candidate->base_addr = base_socket->addr;
|
||
-
|
||
+ candidate->priority = ensure_unique_priority (component,
|
||
+ candidate->priority);
|
||
priv_generate_candidate_credentials (agent, candidate);
|
||
priv_assign_foundation (agent, candidate);
|
||
|
||
@@ -670,8 +673,8 @@ discovery_discover_tcp_server_reflexive_candidates (
|
||
NiceAddress *address,
|
||
NiceSocket *base_socket)
|
||
{
|
||
- Component *component;
|
||
- Stream *stream;
|
||
+ NiceComponent *component;
|
||
+ NiceStream *stream;
|
||
NiceAddress base_addr = base_socket->addr;
|
||
GSList *i;
|
||
|
||
@@ -718,8 +721,8 @@ discovery_add_relay_candidate (
|
||
TurnServer *turn)
|
||
{
|
||
NiceCandidate *candidate;
|
||
- Component *component;
|
||
- Stream *stream;
|
||
+ NiceComponent *component;
|
||
+ NiceStream *stream;
|
||
NiceSocket *relay_socket = NULL;
|
||
|
||
if (!agent_find_component (agent, stream_id, component_id, &stream, &component))
|
||
@@ -732,6 +735,17 @@ discovery_add_relay_candidate (
|
||
candidate->addr = *address;
|
||
candidate->turn = turn_server_ref (turn);
|
||
|
||
+ /* step: link to the base candidate+socket */
|
||
+ relay_socket = nice_udp_turn_socket_new (agent->main_context, address,
|
||
+ base_socket, &turn->server,
|
||
+ turn->username, turn->password,
|
||
+ agent_to_turn_socket_compatibility (agent));
|
||
+ if (!relay_socket)
|
||
+ goto errors;
|
||
+
|
||
+ candidate->sockptr = relay_socket;
|
||
+ candidate->base_addr = base_socket->addr;
|
||
+
|
||
if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
|
||
candidate->priority = nice_candidate_jingle_priority (candidate);
|
||
} else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
|
||
@@ -745,17 +759,8 @@ discovery_add_relay_candidate (
|
||
agent->reliable, FALSE);
|
||
}
|
||
|
||
- /* step: link to the base candidate+socket */
|
||
- relay_socket = nice_udp_turn_socket_new (agent->main_context, address,
|
||
- base_socket, &turn->server,
|
||
- turn->username, turn->password,
|
||
- agent_to_turn_socket_compatibility (agent));
|
||
- if (!relay_socket)
|
||
- goto errors;
|
||
-
|
||
- candidate->sockptr = relay_socket;
|
||
- candidate->base_addr = base_socket->addr;
|
||
-
|
||
+ candidate->priority = ensure_unique_priority (component,
|
||
+ candidate->priority);
|
||
priv_generate_candidate_credentials (agent, candidate);
|
||
|
||
/* Google uses the turn username as the candidate username */
|
||
@@ -769,7 +774,7 @@ discovery_add_relay_candidate (
|
||
if (!priv_add_local_candidate_pruned (agent, stream_id, component, candidate))
|
||
goto errors;
|
||
|
||
- component_attach_socket (component, relay_socket);
|
||
+ nice_component_attach_socket (component, relay_socket);
|
||
agent_signal_new_candidate (agent, candidate);
|
||
|
||
return candidate;
|
||
@@ -798,8 +803,8 @@ discovery_add_peer_reflexive_candidate (
|
||
NiceCandidate *remote)
|
||
{
|
||
NiceCandidate *candidate;
|
||
- Component *component;
|
||
- Stream *stream;
|
||
+ NiceComponent *component;
|
||
+ NiceStream *stream;
|
||
gboolean result;
|
||
|
||
if (!agent_find_component (agent, stream_id, component_id, &stream, &component))
|
||
@@ -836,6 +841,8 @@ discovery_add_peer_reflexive_candidate (
|
||
agent->reliable, FALSE);
|
||
}
|
||
|
||
+ candidate->priority = ensure_unique_priority (component,
|
||
+ candidate->priority);
|
||
priv_assign_foundation (agent, candidate);
|
||
|
||
if ((agent->compatibility == NICE_COMPATIBILITY_MSN ||
|
||
@@ -891,8 +898,8 @@ discovery_add_peer_reflexive_candidate (
|
||
*/
|
||
NiceCandidate *discovery_learn_remote_peer_reflexive_candidate (
|
||
NiceAgent *agent,
|
||
- Stream *stream,
|
||
- Component *component,
|
||
+ NiceStream *stream,
|
||
+ NiceComponent *component,
|
||
guint32 priority,
|
||
const NiceAddress *remote_address,
|
||
NiceSocket *nicesock,
|
||
@@ -1023,10 +1030,12 @@ static gboolean priv_discovery_tick_unlocked (gpointer pointer)
|
||
(cand->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE ||
|
||
cand->type == NICE_CANDIDATE_TYPE_RELAYED)) {
|
||
|
||
- agent_signal_component_state_change (agent,
|
||
- cand->stream->id,
|
||
- cand->component->id,
|
||
- NICE_COMPONENT_STATE_GATHERING);
|
||
+ if (cand->component->state == NICE_COMPONENT_STATE_DISCONNECTED ||
|
||
+ cand->component->state == NICE_COMPONENT_STATE_FAILED)
|
||
+ agent_signal_component_state_change (agent,
|
||
+ cand->stream->id,
|
||
+ cand->component->id,
|
||
+ NICE_COMPONENT_STATE_GATHERING);
|
||
|
||
if (cand->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE) {
|
||
buffer_len = stun_usage_bind_create (&cand->stun_agent,
|
||
diff --git a/agent/discovery.h b/agent/discovery.h
|
||
index c22ea6a..67e2186 100644
|
||
--- a/agent/discovery.h
|
||
+++ b/agent/discovery.h
|
||
@@ -53,8 +53,8 @@ typedef struct
|
||
GTimeVal next_tick; /* next tick timestamp */
|
||
gboolean pending; /* is discovery in progress? */
|
||
gboolean done; /* is discovery complete? */
|
||
- Stream *stream;
|
||
- Component *component;
|
||
+ NiceStream *stream;
|
||
+ NiceComponent *component;
|
||
TurnServer *turn;
|
||
StunAgent stun_agent;
|
||
StunTimer timer;
|
||
@@ -70,8 +70,8 @@ typedef struct
|
||
NiceSocket *nicesock; /* existing socket to use */
|
||
NiceAddress server; /* STUN/TURN server address */
|
||
NiceCandidate *candidate; /* candidate to refresh */
|
||
- Stream *stream;
|
||
- Component *component;
|
||
+ NiceStream *stream;
|
||
+ NiceComponent *component;
|
||
StunAgent stun_agent;
|
||
GSource *timer_source;
|
||
GSource *tick_source;
|
||
@@ -151,8 +151,8 @@ discovery_add_peer_reflexive_candidate (
|
||
NiceCandidate *
|
||
discovery_learn_remote_peer_reflexive_candidate (
|
||
NiceAgent *agent,
|
||
- Stream *stream,
|
||
- Component *component,
|
||
+ NiceStream *stream,
|
||
+ NiceComponent *component,
|
||
guint32 priority,
|
||
const NiceAddress *remote_address,
|
||
NiceSocket *udp_socket,
|
||
diff --git a/agent/inputstream.c b/agent/inputstream.c
|
||
index b9c5369..58a4a0d 100644
|
||
--- a/agent/inputstream.c
|
||
+++ b/agent/inputstream.c
|
||
@@ -332,8 +332,8 @@ nice_input_stream_close (GInputStream *stream, GCancellable *cancellable,
|
||
GError **error)
|
||
{
|
||
NiceInputStreamPrivate *priv = NICE_INPUT_STREAM (stream)->priv;
|
||
- Component *component = NULL;
|
||
- Stream *_stream = NULL;
|
||
+ NiceComponent *component = NULL;
|
||
+ NiceStream *_stream = NULL;
|
||
NiceAgent *agent; /* owned */
|
||
|
||
/* Has the agent disappeared? */
|
||
@@ -361,8 +361,8 @@ static gboolean
|
||
nice_input_stream_is_readable (GPollableInputStream *stream)
|
||
{
|
||
NiceInputStreamPrivate *priv = NICE_INPUT_STREAM (stream)->priv;
|
||
- Component *component = NULL;
|
||
- Stream *_stream = NULL;
|
||
+ NiceComponent *component = NULL;
|
||
+ NiceStream *_stream = NULL;
|
||
gboolean retval = FALSE;
|
||
GSList *i;
|
||
NiceAgent *agent; /* owned */
|
||
@@ -458,7 +458,7 @@ nice_input_stream_create_source (GPollableInputStream *stream,
|
||
if (agent == NULL)
|
||
goto dummy_source;
|
||
|
||
- component_source = component_input_source_new (agent, priv->stream_id,
|
||
+ component_source = nice_component_input_source_new (agent, priv->stream_id,
|
||
priv->component_id, stream, cancellable);
|
||
|
||
g_object_unref (agent);
|
||
diff --git a/agent/outputstream.c b/agent/outputstream.c
|
||
index d479aa5..4c918a7 100644
|
||
--- a/agent/outputstream.c
|
||
+++ b/agent/outputstream.c
|
||
@@ -476,8 +476,8 @@ nice_output_stream_close (GOutputStream *stream, GCancellable *cancellable,
|
||
GError **error)
|
||
{
|
||
NiceOutputStreamPrivate *priv = NICE_OUTPUT_STREAM (stream)->priv;
|
||
- Component *component = NULL;
|
||
- Stream *_stream = NULL;
|
||
+ NiceComponent *component = NULL;
|
||
+ NiceStream *_stream = NULL;
|
||
NiceAgent *agent; /* owned */
|
||
|
||
/* Has the agent disappeared? */
|
||
@@ -505,8 +505,8 @@ static gboolean
|
||
nice_output_stream_is_writable (GPollableOutputStream *stream)
|
||
{
|
||
NiceOutputStreamPrivate *priv = NICE_OUTPUT_STREAM (stream)->priv;
|
||
- Component *component = NULL;
|
||
- Stream *_stream = NULL;
|
||
+ NiceComponent *component = NULL;
|
||
+ NiceStream *_stream = NULL;
|
||
gboolean retval = FALSE;
|
||
NiceAgent *agent; /* owned */
|
||
|
||
@@ -595,8 +595,8 @@ nice_output_stream_create_source (GPollableOutputStream *stream,
|
||
{
|
||
NiceOutputStreamPrivate *priv = NICE_OUTPUT_STREAM (stream)->priv;
|
||
GSource *component_source = NULL;
|
||
- Component *component = NULL;
|
||
- Stream *_stream = NULL;
|
||
+ NiceComponent *component = NULL;
|
||
+ NiceStream *_stream = NULL;
|
||
NiceAgent *agent; /* owned */
|
||
|
||
component_source = g_pollable_source_new (G_OBJECT (stream));
|
||
diff --git a/agent/pseudotcp.c b/agent/pseudotcp.c
|
||
index eb91e3c..3160c34 100644
|
||
--- a/agent/pseudotcp.c
|
||
+++ b/agent/pseudotcp.c
|
||
@@ -77,8 +77,19 @@
|
||
#include "pseudotcp.h"
|
||
#include "agent-priv.h"
|
||
|
||
-G_DEFINE_TYPE (PseudoTcpSocket, pseudo_tcp_socket, G_TYPE_OBJECT);
|
||
+struct _PseudoTcpSocketClass {
|
||
+ GObjectClass parent_class;
|
||
+};
|
||
+
|
||
+typedef struct _PseudoTcpSocketPrivate PseudoTcpSocketPrivate;
|
||
+
|
||
+
|
||
+struct _PseudoTcpSocket {
|
||
+ GObject parent;
|
||
+ PseudoTcpSocketPrivate *priv;
|
||
+};
|
||
|
||
+G_DEFINE_TYPE (PseudoTcpSocket, pseudo_tcp_socket, G_TYPE_OBJECT);
|
||
|
||
//////////////////////////////////////////////////////////////////////
|
||
// Network Constants
|
||
@@ -107,7 +118,9 @@ const guint16 PACKET_MAXIMUMS[] = {
|
||
0, // End of list marker
|
||
};
|
||
|
||
-#define MAX_PACKET 65535
|
||
+// FIXME: This is a reasonable MTU, but we should get it from the lower layer
|
||
+#define DEF_MTU 1400
|
||
+#define MAX_PACKET 65532
|
||
// Note: we removed lowest level because packet overhead was larger!
|
||
#define MIN_PACKET 296
|
||
|
||
@@ -151,8 +164,8 @@ const guint16 PACKET_MAXIMUMS[] = {
|
||
#define PACKET_OVERHEAD (HEADER_SIZE + UDP_HEADER_SIZE + \
|
||
IP_HEADER_SIZE + JINGLE_HEADER_SIZE)
|
||
|
||
-// MIN_RTO = 250 ms (RFC1122, Sec 4.2.3.1 "fractions of a second")
|
||
-#define MIN_RTO 250
|
||
+// MIN_RTO = 1 second (RFC6298, Sec 2.4)
|
||
+#define MIN_RTO 1000
|
||
#define DEF_RTO 1000 /* 1 seconds (RFC 6298 sect 2.1) */
|
||
#define MAX_RTO 60000 /* 60 seconds */
|
||
#define DEFAULT_ACK_DELAY 100 /* 100 milliseconds */
|
||
@@ -416,6 +429,7 @@ typedef enum {
|
||
sfImmediateAck,
|
||
sfFin,
|
||
sfRst,
|
||
+ sfDuplicateAck,
|
||
} SendFlags;
|
||
|
||
typedef struct {
|
||
@@ -471,6 +485,7 @@ struct _PseudoTcpSocketPrivate {
|
||
guint32 rbuf_len, rcv_nxt, rcv_wnd, lastrecv;
|
||
guint8 rwnd_scale; // Window scale factor
|
||
PseudoTcpFifo rbuf;
|
||
+ guint32 rcv_fin; /* sequence number of the received FIN octet, or 0 */
|
||
|
||
// Outgoing data
|
||
GQueue slist;
|
||
@@ -495,7 +510,9 @@ struct _PseudoTcpSocketPrivate {
|
||
guint32 ssthresh, cwnd;
|
||
guint8 dup_acks;
|
||
guint32 recover;
|
||
+ gboolean fast_recovery;
|
||
guint32 t_ack; /* time a delayed ack was scheduled; 0 if no acks scheduled */
|
||
+ guint32 last_acked_ts;
|
||
|
||
gboolean use_nagling;
|
||
guint32 ack_delay;
|
||
@@ -550,7 +567,7 @@ static gboolean parse (PseudoTcpSocket *self,
|
||
const guint8 *_header_buf, gsize header_buf_len,
|
||
const guint8 *data_buf, gsize data_buf_len);
|
||
static gboolean process(PseudoTcpSocket *self, Segment *seg);
|
||
-static gboolean transmit(PseudoTcpSocket *self, SSegment *sseg, guint32 now);
|
||
+static int transmit(PseudoTcpSocket *self, SSegment *sseg, guint32 now);
|
||
static void attempt_send(PseudoTcpSocket *self, SendFlags sflags);
|
||
static void closedown (PseudoTcpSocket *self, guint32 err,
|
||
ClosedownSource source);
|
||
@@ -566,6 +583,7 @@ static void set_state_closed (PseudoTcpSocket *self, guint32 err);
|
||
static const gchar *pseudo_tcp_state_get_name (PseudoTcpState state);
|
||
static gboolean pseudo_tcp_state_has_sent_fin (PseudoTcpState state);
|
||
static gboolean pseudo_tcp_state_has_received_fin (PseudoTcpState state);
|
||
+static gboolean pseudo_tcp_state_has_received_fin_ack (PseudoTcpState state);
|
||
|
||
// The following logging is for detailed (packet-level) pseudotcp analysis only.
|
||
static PseudoTcpDebugLevel debug_level = PSEUDO_TCP_DEBUG_NONE;
|
||
@@ -809,12 +827,14 @@ pseudo_tcp_socket_init (PseudoTcpSocket *obj)
|
||
priv->snd_una = priv->rcv_nxt = 0;
|
||
priv->bReadEnable = TRUE;
|
||
priv->bWriteEnable = FALSE;
|
||
+ priv->rcv_fin = 0;
|
||
+
|
||
priv->t_ack = 0;
|
||
|
||
priv->msslevel = 0;
|
||
priv->largest = 0;
|
||
priv->mss = MIN_PACKET - PACKET_OVERHEAD;
|
||
- priv->mtu_advise = MAX_PACKET;
|
||
+ priv->mtu_advise = DEF_MTU;
|
||
|
||
priv->rto_base = 0;
|
||
|
||
@@ -825,6 +845,7 @@ pseudo_tcp_socket_init (PseudoTcpSocket *obj)
|
||
|
||
priv->dup_acks = 0;
|
||
priv->recover = 0;
|
||
+ priv->last_acked_ts = 0;
|
||
|
||
priv->ts_recent = priv->ts_lastack = 0;
|
||
|
||
@@ -959,18 +980,24 @@ pseudo_tcp_socket_notify_clock(PseudoTcpSocket *self)
|
||
// retransmit segments
|
||
guint32 nInFlight;
|
||
guint32 rto_limit;
|
||
+ int transmit_status;
|
||
|
||
DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "timeout retransmit (rto: %u) "
|
||
"(rto_base: %u) (now: %u) (dup_acks: %u)",
|
||
priv->rx_rto, priv->rto_base, now, (guint) priv->dup_acks);
|
||
|
||
- if (!transmit(self, g_queue_peek_head (&priv->slist), now)) {
|
||
- closedown (self, ECONNABORTED, CLOSEDOWN_LOCAL);
|
||
+ transmit_status = transmit(self, g_queue_peek_head (&priv->slist), now);
|
||
+ if (transmit_status != 0) {
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_NORMAL,
|
||
+ "Error transmitting segment. Closing down.");
|
||
+ closedown (self, transmit_status, CLOSEDOWN_LOCAL);
|
||
return;
|
||
}
|
||
|
||
nInFlight = priv->snd_nxt - priv->snd_una;
|
||
priv->ssthresh = max(nInFlight / 2, 2 * priv->mss);
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "ssthresh: %u = (nInFlight: %u / 2) + "
|
||
+ "2 * mss: %u", priv->ssthresh, nInFlight, priv->mss);
|
||
//LOG(LS_INFO) << "priv->ssthresh: " << priv->ssthresh << " nInFlight: " << nInFlight << " priv->mss: " << priv->mss;
|
||
priv->cwnd = priv->mss;
|
||
|
||
@@ -978,6 +1005,13 @@ pseudo_tcp_socket_notify_clock(PseudoTcpSocket *self)
|
||
rto_limit = (priv->state < TCP_ESTABLISHED) ? DEF_RTO : MAX_RTO;
|
||
priv->rx_rto = min(rto_limit, priv->rx_rto * 2);
|
||
priv->rto_base = now;
|
||
+
|
||
+ priv->recover = priv->snd_nxt;
|
||
+ if (priv->dup_acks >= 3) {
|
||
+ priv->dup_acks = 0;
|
||
+ priv->fast_recovery = FALSE;
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "exit recovery on timeout");
|
||
+ }
|
||
}
|
||
}
|
||
|
||
@@ -985,6 +1019,7 @@ pseudo_tcp_socket_notify_clock(PseudoTcpSocket *self)
|
||
if ((priv->snd_wnd == 0)
|
||
&& (time_diff(priv->lastsend + priv->rx_rto, now) <= 0)) {
|
||
if (time_diff(now, priv->lastrecv) >= 15000) {
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Receive window closed. Closing down.");
|
||
closedown (self, ECONNABORTED, CLOSEDOWN_LOCAL);
|
||
return;
|
||
}
|
||
@@ -1012,9 +1047,11 @@ pseudo_tcp_socket_notify_packet(PseudoTcpSocket *self,
|
||
|
||
if (len > MAX_PACKET) {
|
||
//LOG_F(WARNING) << "packet too large";
|
||
+ self->priv->error = EMSGSIZE;
|
||
return FALSE;
|
||
} else if (len < HEADER_SIZE) {
|
||
//LOG_F(WARNING) << "packet too small";
|
||
+ self->priv->error = EINVAL;
|
||
return FALSE;
|
||
}
|
||
|
||
@@ -1149,9 +1186,7 @@ pseudo_tcp_socket_recv(PseudoTcpSocket *self, char * buffer, size_t len)
|
||
gsize available_space;
|
||
|
||
/* Received a FIN from the peer, so return 0. RFC 793, §3.5, Case 2. */
|
||
- if (priv->support_fin_ack &&
|
||
- (priv->shutdown_reads ||
|
||
- pseudo_tcp_state_has_received_fin (priv->state))) {
|
||
+ if (priv->support_fin_ack && priv->shutdown_reads) {
|
||
return 0;
|
||
}
|
||
|
||
@@ -1173,7 +1208,9 @@ pseudo_tcp_socket_recv(PseudoTcpSocket *self, char * buffer, size_t len)
|
||
bytesread = pseudo_tcp_fifo_read (&priv->rbuf, (guint8 *) buffer, len);
|
||
|
||
// If there's no data in |m_rbuf|.
|
||
- if (bytesread == 0) {
|
||
+ if (bytesread == 0 &&
|
||
+ !(pseudo_tcp_state_has_received_fin (priv->state) ||
|
||
+ pseudo_tcp_state_has_received_fin_ack (priv->state))) {
|
||
priv->bReadEnable = TRUE;
|
||
priv->error = EWOULDBLOCK;
|
||
return -1;
|
||
@@ -1407,7 +1444,7 @@ packet(PseudoTcpSocket *self, guint32 seq, TcpFlags flags,
|
||
g_assert (bytes_read == len);
|
||
}
|
||
|
||
- DEBUG (PSEUDO_TCP_DEBUG_VERBOSE, "<-- <CONV=%u><FLG=%u><SEQ=%u:%u><ACK=%u>"
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_VERBOSE, "Sending <CONV=%u><FLG=%u><SEQ=%u:%u><ACK=%u>"
|
||
"<WND=%u><TS=%u><TSR=%u><LEN=%u>",
|
||
priv->conv, (unsigned)flags, seq, seq + len, priv->rcv_nxt, priv->rcv_wnd,
|
||
now % 10000, priv->ts_recent % 10000, len);
|
||
@@ -1460,7 +1497,8 @@ parse (PseudoTcpSocket *self, const guint8 *_header_buf, gsize header_buf_len,
|
||
seg.data = (const gchar *) data_buf;
|
||
seg.len = data_buf_len;
|
||
|
||
- DEBUG (PSEUDO_TCP_DEBUG_VERBOSE, "--> <CONV=%u><FLG=%u><SEQ=%u:%u><ACK=%u>"
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_VERBOSE,
|
||
+ "Received <CONV=%u><FLG=%u><SEQ=%u:%u><ACK=%u>"
|
||
"<WND=%u><TS=%u><TSR=%u><LEN=%u>",
|
||
seg.conv, (unsigned)seg.flags, seg.seq, seg.seq + seg.len, seg.ack,
|
||
seg.wnd, seg.tsval % 10000, seg.tsecr % 10000, seg.len);
|
||
@@ -1516,6 +1554,30 @@ pseudo_tcp_state_has_received_fin (PseudoTcpState state)
|
||
}
|
||
}
|
||
|
||
+/* True iff the @state requires that a FIN-ACK has already been received from
|
||
+ * the peer. */
|
||
+static gboolean
|
||
+pseudo_tcp_state_has_received_fin_ack (PseudoTcpState state)
|
||
+{
|
||
+ switch (state) {
|
||
+ case TCP_LISTEN:
|
||
+ case TCP_SYN_SENT:
|
||
+ case TCP_SYN_RECEIVED:
|
||
+ case TCP_ESTABLISHED:
|
||
+ case TCP_FIN_WAIT_1:
|
||
+ case TCP_FIN_WAIT_2:
|
||
+ case TCP_CLOSING:
|
||
+ case TCP_CLOSE_WAIT:
|
||
+ case TCP_LAST_ACK:
|
||
+ return FALSE;
|
||
+ case TCP_CLOSED:
|
||
+ case TCP_TIME_WAIT:
|
||
+ return TRUE;
|
||
+ default:
|
||
+ return FALSE;
|
||
+ }
|
||
+}
|
||
+
|
||
static gboolean
|
||
process(PseudoTcpSocket *self, Segment *seg)
|
||
{
|
||
@@ -1529,6 +1591,7 @@ process(PseudoTcpSocket *self, Segment *seg)
|
||
gsize available_space;
|
||
guint32 kIdealRefillSize;
|
||
gboolean is_valuable_ack, is_duplicate_ack, is_fin_ack = FALSE;
|
||
+ gboolean received_fin = FALSE;
|
||
|
||
/* If this is the wrong conversation, send a reset!?!
|
||
(with the correct conversation?) */
|
||
@@ -1545,17 +1608,23 @@ process(PseudoTcpSocket *self, Segment *seg)
|
||
priv->bOutgoing = FALSE;
|
||
|
||
if (priv->state == TCP_CLOSED ||
|
||
- (pseudo_tcp_state_has_sent_fin (priv->state) && seg->len > 0)) {
|
||
- /* Send an RST segment. See: RFC 1122, §4.2.2.13. */
|
||
+ (pseudo_tcp_state_has_received_fin_ack (priv->state) && seg->len > 0)) {
|
||
+ /* Send an RST segment. See: RFC 1122, §4.2.2.13; RFC 793, §3.4, point 3,
|
||
+ * page 37. We can only send RST if we know the peer knows we’re closed;
|
||
+ * otherwise this could be a timeout retransmit from them, due to our
|
||
+ * packets from data through to FIN being dropped. */
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_NORMAL,
|
||
+ "Segment received while closed; sending RST.");
|
||
if ((seg->flags & FLAG_RST) == 0) {
|
||
closedown (self, 0, CLOSEDOWN_LOCAL);
|
||
}
|
||
- DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Segment received while closed; sent RST.");
|
||
+
|
||
return FALSE;
|
||
}
|
||
|
||
// Check if this is a reset segment
|
||
if (seg->flags & FLAG_RST) {
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Received RST segment; closing down.");
|
||
closedown (self, ECONNRESET, CLOSEDOWN_REMOTE);
|
||
return FALSE;
|
||
}
|
||
@@ -1607,18 +1676,20 @@ process(PseudoTcpSocket *self, Segment *seg)
|
||
priv->rx_rttvar = rtt / 2;
|
||
} else {
|
||
priv->rx_rttvar = (3 * priv->rx_rttvar +
|
||
- abs((long)(rtt - priv->rx_srtt))) / 4;
|
||
+ labs((long)(rtt - priv->rx_srtt))) / 4;
|
||
priv->rx_srtt = (7 * priv->rx_srtt + rtt) / 8;
|
||
}
|
||
priv->rx_rto = bound(MIN_RTO,
|
||
priv->rx_srtt + max(1LU, 4 * priv->rx_rttvar), MAX_RTO);
|
||
|
||
- DEBUG (PSEUDO_TCP_DEBUG_VERBOSE, "rtt: %ld srtt: %u rto: %u",
|
||
- rtt, priv->rx_srtt, priv->rx_rto);
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_VERBOSE, "rtt: %ld srtt: %u rttvar: %u rto: %u",
|
||
+ rtt, priv->rx_srtt, priv->rx_rttvar, priv->rx_rto);
|
||
} else {
|
||
DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Invalid RTT: %ld", rtt);
|
||
return FALSE;
|
||
}
|
||
+
|
||
+ priv->last_acked_ts = seg->tsecr;
|
||
}
|
||
|
||
priv->snd_wnd = seg->wnd << priv->swnd_scale;
|
||
@@ -1663,16 +1734,24 @@ process(PseudoTcpSocket *self, Segment *seg)
|
||
if (LARGER_OR_EQUAL (priv->snd_una, priv->recover)) { // NewReno
|
||
guint32 nInFlight = priv->snd_nxt - priv->snd_una;
|
||
// (Fast Retransmit)
|
||
- priv->cwnd = min(priv->ssthresh, nInFlight + priv->mss);
|
||
- DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "exit recovery");
|
||
+ priv->cwnd = min(priv->ssthresh,
|
||
+ max (nInFlight, priv->mss) + priv->mss);
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "exit recovery cwnd=%d ssthresh=%d nInFlight=%d mss: %d", priv->cwnd, priv->ssthresh, nInFlight, priv->mss);
|
||
+ priv->fast_recovery = FALSE;
|
||
priv->dup_acks = 0;
|
||
} else {
|
||
+ int transmit_status;
|
||
+
|
||
DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "recovery retransmit");
|
||
- if (!transmit(self, g_queue_peek_head (&priv->slist), now)) {
|
||
- closedown (self, ECONNABORTED, CLOSEDOWN_LOCAL);
|
||
+ transmit_status = transmit(self, g_queue_peek_head (&priv->slist), now);
|
||
+ if (transmit_status != 0) {
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_NORMAL,
|
||
+ "Error transmitting recovery retransmit segment. Closing down.");
|
||
+ closedown (self, transmit_status, CLOSEDOWN_LOCAL);
|
||
return FALSE;
|
||
}
|
||
- priv->cwnd += priv->mss - min(nAcked, priv->cwnd);
|
||
+ priv->cwnd += (nAcked > priv->mss ? priv->mss : 0) -
|
||
+ min(nAcked, priv->cwnd);
|
||
}
|
||
} else {
|
||
priv->dup_acks = 0;
|
||
@@ -1695,20 +1774,43 @@ process(PseudoTcpSocket *self, Segment *seg)
|
||
guint32 nInFlight;
|
||
|
||
priv->dup_acks += 1;
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_VERBOSE, "Received dup ack (dups: %u)",
|
||
+ priv->dup_acks);
|
||
if (priv->dup_acks == 3) { // (Fast Retransmit)
|
||
- DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "enter recovery");
|
||
- DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "recovery retransmit");
|
||
- if (!transmit(self, g_queue_peek_head (&priv->slist), now)) {
|
||
- closedown (self, ECONNABORTED, CLOSEDOWN_LOCAL);
|
||
- return FALSE;
|
||
+ int transmit_status;
|
||
+
|
||
+
|
||
+ if (LARGER_OR_EQUAL (priv->snd_una, priv->recover) ||
|
||
+ seg->tsecr == priv->last_acked_ts) { /* NewReno */
|
||
+ /* Invoke fast retransmit RFC3782 section 3 step 1A*/
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "enter recovery");
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "recovery retransmit");
|
||
+
|
||
+ transmit_status = transmit(self, g_queue_peek_head (&priv->slist),
|
||
+ now);
|
||
+ if (transmit_status != 0) {
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_NORMAL,
|
||
+ "Error transmitting recovery retransmit segment. Closing down.");
|
||
+
|
||
+ closedown (self, transmit_status, CLOSEDOWN_LOCAL);
|
||
+ return FALSE;
|
||
+ }
|
||
+ priv->recover = priv->snd_nxt;
|
||
+ nInFlight = priv->snd_nxt - priv->snd_una;
|
||
+ priv->ssthresh = max(nInFlight / 2, 2 * priv->mss);
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_NORMAL,
|
||
+ "ssthresh: %u = max((nInFlight: %u / 2), 2 * mss: %u)",
|
||
+ priv->ssthresh, nInFlight, priv->mss);
|
||
+ priv->cwnd = priv->ssthresh + 3 * priv->mss;
|
||
+ priv->fast_recovery = TRUE;
|
||
+ } else {
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_VERBOSE,
|
||
+ "Skipping fast recovery: recover: %u snd_una: %u", priv->recover,
|
||
+ priv->snd_una);
|
||
}
|
||
- priv->recover = priv->snd_nxt;
|
||
- nInFlight = priv->snd_nxt - priv->snd_una;
|
||
- priv->ssthresh = max(nInFlight / 2, 2 * priv->mss);
|
||
- //LOG(LS_INFO) << "priv->ssthresh: " << priv->ssthresh << " nInFlight: " << nInFlight << " priv->mss: " << priv->mss;
|
||
- priv->cwnd = priv->ssthresh + 3 * priv->mss;
|
||
} else if (priv->dup_acks > 3) {
|
||
- priv->cwnd += priv->mss;
|
||
+ if (priv->fast_recovery)
|
||
+ priv->cwnd += priv->mss;
|
||
}
|
||
} else {
|
||
priv->dup_acks = 0;
|
||
@@ -1720,19 +1822,34 @@ process(PseudoTcpSocket *self, Segment *seg)
|
||
set_state_established (self);
|
||
}
|
||
|
||
- /* Check for connection closure. */
|
||
+ /* Check for connection closure. Only pay attention to FIN segments if they
|
||
+ * are in sequence; otherwise we’ve missed a packet earlier in the stream and
|
||
+ * need to request retransmission first. */
|
||
if (priv->support_fin_ack) {
|
||
+ /* @received_fin is set when, and only when, all segments preceding the FIN
|
||
+ * have been acknowledged. This is to handle the case where the FIN arrives
|
||
+ * out of order with a preceding data segment. */
|
||
+ if (seg->flags & FLAG_FIN && priv->rcv_fin == 0) {
|
||
+ priv->rcv_fin = seg->seq;
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Setting rcv_fin = %u", priv->rcv_fin);
|
||
+ } else if (seg->flags & FLAG_FIN && seg->seq != priv->rcv_fin) {
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Second FIN segment received; ignored");
|
||
+ return FALSE;
|
||
+ }
|
||
+
|
||
/* For the moment, FIN segments must not contain data. */
|
||
if (seg->flags & FLAG_FIN && seg->len != 0) {
|
||
DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "FIN segment contained data; ignored");
|
||
return FALSE;
|
||
}
|
||
|
||
+ received_fin = (priv->rcv_nxt != 0 && priv->rcv_nxt + seg->len == priv->rcv_fin);
|
||
+
|
||
/* Update the state machine, implementing all transitions on ‘rcv FIN’ or
|
||
* ‘rcv ACK of FIN’ from RFC 793, Figure 6; and RFC 1122, §4.2.2.8. */
|
||
switch (priv->state) {
|
||
case TCP_ESTABLISHED:
|
||
- if (seg->flags & FLAG_FIN) {
|
||
+ if (received_fin) {
|
||
/* Received a FIN from the network, RFC 793, §3.5, Case 2.
|
||
* The code below will send an ACK for the FIN. */
|
||
set_state (self, TCP_CLOSE_WAIT);
|
||
@@ -1751,20 +1868,20 @@ process(PseudoTcpSocket *self, Segment *seg)
|
||
}
|
||
break;
|
||
case TCP_FIN_WAIT_1:
|
||
- if (is_fin_ack && seg->flags & FLAG_FIN) {
|
||
+ if (is_fin_ack && received_fin) {
|
||
/* Simultaneous close with an ACK for a FIN previously sent,
|
||
* RFC 793, §3.5, Case 3. */
|
||
set_state (self, TCP_TIME_WAIT);
|
||
} else if (is_fin_ack) {
|
||
/* Handle the ACK of a locally-sent FIN flag. RFC 793, §3.5, Case 1. */
|
||
set_state (self, TCP_FIN_WAIT_2);
|
||
- } else if (seg->flags & FLAG_FIN) {
|
||
+ } else if (received_fin) {
|
||
/* Simultaneous close, RFC 793, §3.5, Case 3. */
|
||
set_state (self, TCP_CLOSING);
|
||
}
|
||
break;
|
||
case TCP_FIN_WAIT_2:
|
||
- if (seg->flags & FLAG_FIN) {
|
||
+ if (received_fin) {
|
||
/* Local user closed the connection, RFC 793, §3.5, Case 1. */
|
||
set_state (self, TCP_TIME_WAIT);
|
||
}
|
||
@@ -1776,7 +1893,7 @@ process(PseudoTcpSocket *self, Segment *seg)
|
||
case TCP_CLOSED:
|
||
case TCP_CLOSE_WAIT:
|
||
/* Shouldn’t ever hit these cases. */
|
||
- if (seg->flags & FLAG_FIN) {
|
||
+ if (received_fin) {
|
||
DEBUG (PSEUDO_TCP_DEBUG_NORMAL,
|
||
"Unexpected state %u when FIN received", priv->state);
|
||
} else if (is_fin_ack) {
|
||
@@ -1820,19 +1937,20 @@ process(PseudoTcpSocket *self, Segment *seg)
|
||
* see RFC 793, §3.3. Also see: RFC 793, §3.5.
|
||
*/
|
||
if (seg->seq != priv->rcv_nxt) {
|
||
- sflags = sfImmediateAck; // (Fast Recovery)
|
||
+ sflags = sfDuplicateAck; // (Fast Recovery)
|
||
} else if (seg->len != 0) {
|
||
if (priv->ack_delay == 0) {
|
||
sflags = sfImmediateAck;
|
||
} else {
|
||
sflags = sfDelayedAck;
|
||
}
|
||
- } else if (seg->flags & FLAG_FIN) {
|
||
+ } else if (received_fin) {
|
||
+ /* FIN flags have a sequence number. Only acknowledge them after all
|
||
+ * preceding octets have been acknowledged. */
|
||
sflags = sfImmediateAck;
|
||
- priv->rcv_nxt += 1;
|
||
}
|
||
|
||
- if (sflags == sfImmediateAck) {
|
||
+ if (sflags == sfDuplicateAck) {
|
||
if (seg->seq > priv->rcv_nxt) {
|
||
DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "too new");
|
||
} else if (SMALLER_OR_EQUAL(seg->seq + seg->len, priv->rcv_nxt)) {
|
||
@@ -1869,12 +1987,7 @@ process(PseudoTcpSocket *self, Segment *seg)
|
||
|
||
bNewData = FALSE;
|
||
|
||
- if (seg->flags & FLAG_FIN) {
|
||
- /* FIN flags have a sequence number. */
|
||
- if (seg->seq == priv->rcv_nxt) {
|
||
- priv->rcv_nxt++;
|
||
- }
|
||
- } else if (seg->len > 0) {
|
||
+ if (seg->len > 0) {
|
||
if (bIgnoreData) {
|
||
if (seg->seq == priv->rcv_nxt) {
|
||
priv->rcv_nxt += seg->len;
|
||
@@ -1929,6 +2042,12 @@ process(PseudoTcpSocket *self, Segment *seg)
|
||
}
|
||
}
|
||
|
||
+ if (received_fin) {
|
||
+ /* FIN flags have a sequence number. */
|
||
+ priv->rcv_nxt++;
|
||
+ }
|
||
+
|
||
+
|
||
attempt_send(self, sflags);
|
||
|
||
// If we have new data, notify the user
|
||
@@ -1952,7 +2071,7 @@ transmit(PseudoTcpSocket *self, SSegment *segment, guint32 now)
|
||
|
||
if (segment->xmit >= ((priv->state == TCP_ESTABLISHED) ? 15 : 30)) {
|
||
DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "too many retransmits");
|
||
- return FALSE;
|
||
+ return ETIMEDOUT;
|
||
}
|
||
|
||
while (TRUE) {
|
||
@@ -1972,7 +2091,7 @@ transmit(PseudoTcpSocket *self, SSegment *segment, guint32 now)
|
||
|
||
if (wres == WR_FAIL) {
|
||
DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "packet failed");
|
||
- return FALSE;
|
||
+ return ECONNABORTED; /* FIXME: This error code doesn’t quite seem right */
|
||
}
|
||
|
||
g_assert(wres == WR_TOO_LARGE);
|
||
@@ -1980,7 +2099,7 @@ transmit(PseudoTcpSocket *self, SSegment *segment, guint32 now)
|
||
while (TRUE) {
|
||
if (PACKET_MAXIMUMS[priv->msslevel + 1] == 0) {
|
||
DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "MTU too small");
|
||
- return FALSE;
|
||
+ return EMSGSIZE;
|
||
}
|
||
/* !?! We need to break up all outstanding and pending packets
|
||
and then retransmit!?! */
|
||
@@ -2029,7 +2148,7 @@ transmit(PseudoTcpSocket *self, SSegment *segment, guint32 now)
|
||
priv->rto_base = now;
|
||
}
|
||
|
||
- return TRUE;
|
||
+ return 0;
|
||
}
|
||
|
||
static void
|
||
@@ -2039,6 +2158,8 @@ attempt_send(PseudoTcpSocket *self, SendFlags sflags)
|
||
guint32 now = get_current_time (self);
|
||
gboolean bFirst = TRUE;
|
||
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Attempting send with flags %u.", sflags);
|
||
+
|
||
if (time_diff(now, priv->lastsend) > (long) priv->rx_rto) {
|
||
priv->cwnd = priv->mss;
|
||
}
|
||
@@ -2053,6 +2174,7 @@ attempt_send(PseudoTcpSocket *self, SendFlags sflags)
|
||
gsize snd_buffered;
|
||
GList *iter;
|
||
SSegment *sseg;
|
||
+ int transmit_status;
|
||
|
||
cwnd = priv->cwnd;
|
||
if ((priv->dup_acks == 1) || (priv->dup_acks == 2)) { // Limited Transmit
|
||
@@ -2078,12 +2200,19 @@ attempt_send(PseudoTcpSocket *self, SendFlags sflags)
|
||
|
||
if (bFirst) {
|
||
gsize available_space = pseudo_tcp_fifo_get_write_remaining (&priv->sbuf);
|
||
+
|
||
bFirst = FALSE;
|
||
DEBUG (PSEUDO_TCP_DEBUG_VERBOSE, "[cwnd: %u nWindow: %u nInFlight: %u "
|
||
"nAvailable: %u nQueued: %" G_GSIZE_FORMAT " nEmpty: %" G_GSIZE_FORMAT
|
||
- " ssthresh: %u]",
|
||
+ " nWaiting: %zu ssthresh: %u]",
|
||
priv->cwnd, nWindow, nInFlight, nAvailable, snd_buffered,
|
||
- available_space, priv->ssthresh);
|
||
+ available_space, snd_buffered - nInFlight, priv->ssthresh);
|
||
+ }
|
||
+
|
||
+ if (sflags == sfDuplicateAck) {
|
||
+ packet(self, priv->snd_nxt, 0, 0, 0, now);
|
||
+ sflags = sfNone;
|
||
+ continue;
|
||
}
|
||
|
||
if (nAvailable == 0 && sflags != sfFin && sflags != sfRst) {
|
||
@@ -2091,7 +2220,8 @@ attempt_send(PseudoTcpSocket *self, SendFlags sflags)
|
||
return;
|
||
|
||
// If this is an immediate ack, or the second delayed ack
|
||
- if ((sflags == sfImmediateAck) || priv->t_ack) {
|
||
+ if ((sflags == sfImmediateAck || sflags == sfDuplicateAck) ||
|
||
+ priv->t_ack) {
|
||
packet(self, priv->snd_nxt, 0, 0, 0, now);
|
||
} else {
|
||
priv->t_ack = now;
|
||
@@ -2128,9 +2258,12 @@ attempt_send(PseudoTcpSocket *self, SendFlags sflags)
|
||
subseg);
|
||
}
|
||
|
||
- if (!transmit(self, sseg, now)) {
|
||
+ transmit_status = transmit(self, sseg, now);
|
||
+ if (transmit_status != 0) {
|
||
DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "transmit failed");
|
||
- // TODO: consider closing socket
|
||
+
|
||
+ // TODO: Is this the right thing ?
|
||
+ closedown (self, transmit_status, CLOSEDOWN_REMOTE);
|
||
return;
|
||
}
|
||
|
||
@@ -2147,6 +2280,9 @@ closedown (PseudoTcpSocket *self, guint32 err, ClosedownSource source)
|
||
{
|
||
PseudoTcpSocketPrivate *priv = self->priv;
|
||
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Closing down socket %p with %s error %u.",
|
||
+ self, (source == CLOSEDOWN_LOCAL) ? "local" : "remote", err);
|
||
+
|
||
if (source == CLOSEDOWN_LOCAL && priv->support_fin_ack) {
|
||
queue_rst_message (self);
|
||
attempt_send (self, sfRst);
|
||
@@ -2211,6 +2347,7 @@ apply_window_scale_option (PseudoTcpSocket *self, guint8 scale_factor)
|
||
PseudoTcpSocketPrivate *priv = self->priv;
|
||
|
||
priv->swnd_scale = scale_factor;
|
||
+ DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Setting scale factor to %u", scale_factor);
|
||
}
|
||
|
||
static void
|
||
@@ -2375,10 +2512,6 @@ pseudo_tcp_socket_get_available_bytes (PseudoTcpSocket *self)
|
||
{
|
||
PseudoTcpSocketPrivate *priv = self->priv;
|
||
|
||
- if (priv->state != TCP_ESTABLISHED) {
|
||
- return -1;
|
||
- }
|
||
-
|
||
return pseudo_tcp_fifo_get_buffered (&priv->rbuf);
|
||
}
|
||
|
||
@@ -2394,11 +2527,11 @@ pseudo_tcp_socket_get_available_send_space (PseudoTcpSocket *self)
|
||
PseudoTcpSocketPrivate *priv = self->priv;
|
||
gsize ret;
|
||
|
||
-
|
||
- if (priv->state == TCP_ESTABLISHED)
|
||
+ if (!pseudo_tcp_state_has_sent_fin (priv->state)) {
|
||
ret = pseudo_tcp_fifo_get_write_remaining (&priv->sbuf);
|
||
- else
|
||
+ } else {
|
||
ret = 0;
|
||
+ }
|
||
|
||
if (ret == 0)
|
||
priv->bWriteEnable = TRUE;
|
||
diff --git a/agent/pseudotcp.h b/agent/pseudotcp.h
|
||
index 879276e..e7c8eaa 100644
|
||
--- a/agent/pseudotcp.h
|
||
+++ b/agent/pseudotcp.h
|
||
@@ -62,12 +62,24 @@
|
||
#ifndef __GTK_DOC_IGNORE__
|
||
#ifdef G_OS_WIN32
|
||
# include <winsock2.h>
|
||
+
|
||
+#ifndef ECONNABORTED
|
||
# define ECONNABORTED WSAECONNABORTED
|
||
+#endif
|
||
+
|
||
+#ifndef ENOTCONN
|
||
# define ENOTCONN WSAENOTCONN
|
||
+#endif
|
||
+
|
||
+#ifndef EWOULDBLOCK
|
||
# define EWOULDBLOCK WSAEWOULDBLOCK
|
||
+#endif
|
||
+
|
||
+#ifndef ECONNRESET
|
||
# define ECONNRESET WSAECONNRESET
|
||
#endif
|
||
#endif
|
||
+#endif
|
||
|
||
#include "agent.h"
|
||
|
||
@@ -103,17 +115,6 @@ GType pseudo_tcp_socket_get_type (void);
|
||
(G_TYPE_INSTANCE_GET_CLASS ((obj), PSEUDO_TCP_SOCKET_TYPE, \
|
||
PseudoTcpSocketClass))
|
||
|
||
-struct _PseudoTcpSocketClass {
|
||
- GObjectClass parent_class;
|
||
-};
|
||
-
|
||
-typedef struct _PseudoTcpSocketPrivate PseudoTcpSocketPrivate;
|
||
-
|
||
-struct _PseudoTcpSocket {
|
||
- GObject parent;
|
||
- PseudoTcpSocketPrivate *priv;
|
||
-};
|
||
-
|
||
/**
|
||
* PseudoTcpDebugLevel:
|
||
* @PSEUDO_TCP_DEBUG_NONE: Disable debug messages
|
||
diff --git a/agent/stream.c b/agent/stream.c
|
||
index 09f79b5..8121e12 100644
|
||
--- a/agent/stream.c
|
||
+++ b/agent/stream.c
|
||
@@ -48,63 +48,54 @@
|
||
static volatile unsigned int n_streams_created = 0;
|
||
static volatile unsigned int n_streams_destroyed = 0;
|
||
|
||
+G_DEFINE_TYPE (NiceStream, nice_stream, G_TYPE_OBJECT);
|
||
+
|
||
+static void
|
||
+nice_stream_finalize (GObject *obj);
|
||
+
|
||
/*
|
||
* @file stream.c
|
||
* @brief ICE stream functionality
|
||
*/
|
||
-Stream *
|
||
-stream_new (guint n_components, NiceAgent *agent)
|
||
+NiceStream *
|
||
+nice_stream_new (guint n_components, NiceAgent *agent)
|
||
{
|
||
- Stream *stream;
|
||
+ NiceStream *stream = NULL;
|
||
guint n;
|
||
- Component *component;
|
||
|
||
- g_atomic_int_inc (&n_streams_created);
|
||
- nice_debug ("Created NiceStream (%u created, %u destroyed)",
|
||
- n_streams_created, n_streams_destroyed);
|
||
+ stream = g_object_new (NICE_TYPE_STREAM, NULL);
|
||
|
||
- stream = g_slice_new0 (Stream);
|
||
+ /* Create the components. */
|
||
for (n = 0; n < n_components; n++) {
|
||
- component = component_new (n + 1, agent, stream);
|
||
+ NiceComponent *component = NULL;
|
||
+
|
||
+ component = nice_component_new (n + 1, agent, stream);
|
||
stream->components = g_slist_append (stream->components, component);
|
||
}
|
||
|
||
stream->n_components = n_components;
|
||
- stream->initial_binding_request_received = FALSE;
|
||
|
||
return stream;
|
||
}
|
||
|
||
void
|
||
-stream_close (Stream *stream)
|
||
+nice_stream_close (NiceStream *stream)
|
||
{
|
||
GSList *i;
|
||
|
||
for (i = stream->components; i; i = i->next) {
|
||
- Component *component = i->data;
|
||
- component_close (component);
|
||
+ NiceComponent *component = i->data;
|
||
+ nice_component_close (component);
|
||
}
|
||
}
|
||
|
||
-void
|
||
-stream_free (Stream *stream)
|
||
-{
|
||
- g_free (stream->name);
|
||
- g_slist_free_full (stream->components, (GDestroyNotify) component_free);
|
||
- g_slice_free (Stream, stream);
|
||
-
|
||
- g_atomic_int_inc (&n_streams_destroyed);
|
||
- nice_debug ("Destroyed NiceStream (%u created, %u destroyed)",
|
||
- n_streams_created, n_streams_destroyed);
|
||
-}
|
||
-
|
||
-Component *
|
||
-stream_find_component_by_id (const Stream *stream, guint id)
|
||
+NiceComponent *
|
||
+nice_stream_find_component_by_id (NiceStream *stream, guint id)
|
||
{
|
||
GSList *i;
|
||
|
||
for (i = stream->components; i; i = i->next) {
|
||
- Component *component = i->data;
|
||
+ NiceComponent *component = i->data;
|
||
if (component && component->id == id)
|
||
return component;
|
||
}
|
||
@@ -117,12 +108,12 @@ stream_find_component_by_id (const Stream *stream, guint id)
|
||
* 'CONNECTED' or 'READY' (connected plus nominated).
|
||
*/
|
||
gboolean
|
||
-stream_all_components_ready (const Stream *stream)
|
||
+nice_stream_all_components_ready (NiceStream *stream)
|
||
{
|
||
GSList *i;
|
||
|
||
for (i = stream->components; i; i = i->next) {
|
||
- Component *component = i->data;
|
||
+ NiceComponent *component = i->data;
|
||
if (component &&
|
||
!(component->state == NICE_COMPONENT_STATE_CONNECTED ||
|
||
component->state == NICE_COMPONENT_STATE_READY))
|
||
@@ -136,7 +127,8 @@ stream_all_components_ready (const Stream *stream)
|
||
/*
|
||
* Initialized the local crendentials for the stream.
|
||
*/
|
||
-void stream_initialize_credentials (Stream *stream, NiceRNG *rng)
|
||
+void
|
||
+nice_stream_initialize_credentials (NiceStream *stream, NiceRNG *rng)
|
||
{
|
||
/* note: generate ufrag/pwd for the stream (see ICE 15.4.
|
||
* '"ice-ufrag" and "ice-pwd" Attributes', ID-19) */
|
||
@@ -149,7 +141,7 @@ void stream_initialize_credentials (Stream *stream, NiceRNG *rng)
|
||
* session.
|
||
*/
|
||
void
|
||
-stream_restart (NiceAgent *agent, Stream *stream)
|
||
+nice_stream_restart (NiceStream *stream, NiceAgent *agent)
|
||
{
|
||
GSList *i;
|
||
|
||
@@ -158,12 +150,49 @@ stream_restart (NiceAgent *agent, Stream *stream)
|
||
|
||
stream->initial_binding_request_received = FALSE;
|
||
|
||
- stream_initialize_credentials (stream, agent->rng);
|
||
+ nice_stream_initialize_credentials (stream, agent->rng);
|
||
|
||
for (i = stream->components; i; i = i->next) {
|
||
- Component *component = i->data;
|
||
+ NiceComponent *component = i->data;
|
||
|
||
- component_restart (component);
|
||
+ nice_component_restart (component);
|
||
}
|
||
}
|
||
|
||
+static void
|
||
+nice_stream_class_init (NiceStreamClass *klass)
|
||
+{
|
||
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||
+
|
||
+ object_class->finalize = nice_stream_finalize;
|
||
+}
|
||
+
|
||
+static void
|
||
+nice_stream_init (NiceStream *stream)
|
||
+{
|
||
+ g_atomic_int_inc (&n_streams_created);
|
||
+ nice_debug ("Created NiceStream (%u created, %u destroyed)",
|
||
+ n_streams_created, n_streams_destroyed);
|
||
+
|
||
+ stream->n_components = 0;
|
||
+ stream->initial_binding_request_received = FALSE;
|
||
+}
|
||
+
|
||
+/* Must be called with the agent lock released as it could dispose of
|
||
+ * NiceIOStreams. */
|
||
+static void
|
||
+nice_stream_finalize (GObject *obj)
|
||
+{
|
||
+ NiceStream *stream;
|
||
+
|
||
+ stream = NICE_STREAM (obj);
|
||
+
|
||
+ g_free (stream->name);
|
||
+ g_slist_free_full (stream->components, (GDestroyNotify) g_object_unref);
|
||
+
|
||
+ g_atomic_int_inc (&n_streams_destroyed);
|
||
+ nice_debug ("Destroyed NiceStream (%u created, %u destroyed)",
|
||
+ n_streams_created, n_streams_destroyed);
|
||
+
|
||
+ G_OBJECT_CLASS (nice_stream_parent_class)->finalize (obj);
|
||
+}
|
||
diff --git a/agent/stream.h b/agent/stream.h
|
||
index e220f43..e524f62 100644
|
||
--- a/agent/stream.h
|
||
+++ b/agent/stream.h
|
||
@@ -42,7 +42,7 @@
|
||
|
||
#include <glib.h>
|
||
|
||
-typedef struct _Stream Stream;
|
||
+typedef struct _NiceStream NiceStream;
|
||
|
||
#include "component.h"
|
||
#include "random.h"
|
||
@@ -59,13 +59,27 @@ G_BEGIN_DECLS
|
||
#define NICE_STREAM_DEF_UFRAG 4 + 1 /* ufrag + NULL */
|
||
#define NICE_STREAM_DEF_PWD 22 + 1 /* pwd + NULL */
|
||
|
||
-struct _Stream
|
||
-{
|
||
+#define NICE_TYPE_STREAM nice_stream_get_type()
|
||
+#define NICE_STREAM(obj) \
|
||
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), NICE_TYPE_STREAM, NiceStream))
|
||
+#define NICE_STREAM_CLASS(klass) \
|
||
+ (G_TYPE_CHECK_CLASS_CAST ((klass), NICE_TYPE_STREAM, NiceStreamClass))
|
||
+#define NICE_IS_STREAM(obj) \
|
||
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NICE_TYPE_STREAM))
|
||
+#define NICE_IS_STREAM_CLASS(klass) \
|
||
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), NICE_TYPE_STREAM))
|
||
+#define NICE_STREAM_GET_CLASS(obj) \
|
||
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), NICE_TYPE_STREAM, NiceStreamClass))
|
||
+
|
||
+struct _NiceStream {
|
||
+ /*< private >*/
|
||
+ GObject parent;
|
||
+
|
||
gchar *name;
|
||
guint id;
|
||
guint n_components;
|
||
gboolean initial_binding_request_received;
|
||
- GSList *components; /* list of 'Component' structs */
|
||
+ GSList *components; /* list of 'NiceComponent' objects */
|
||
GSList *conncheck_list; /* list of CandidateCheckPair items */
|
||
gchar local_ufrag[NICE_STREAM_MAX_UFRAG];
|
||
gchar local_password[NICE_STREAM_MAX_PWD];
|
||
@@ -76,27 +90,29 @@ struct _Stream
|
||
gint tos;
|
||
};
|
||
|
||
+typedef struct {
|
||
+ GObjectClass parent_class;
|
||
+} NiceStreamClass;
|
||
|
||
-Stream *
|
||
-stream_new (guint n_components, NiceAgent *agent);
|
||
+GType nice_stream_get_type (void);
|
||
|
||
-void
|
||
-stream_close (Stream *stream);
|
||
+NiceStream *
|
||
+nice_stream_new (guint n_components, NiceAgent *agent);
|
||
|
||
void
|
||
-stream_free (Stream *stream);
|
||
+nice_stream_close (NiceStream *stream);
|
||
|
||
gboolean
|
||
-stream_all_components_ready (const Stream *stream);
|
||
+nice_stream_all_components_ready (NiceStream *stream);
|
||
|
||
-Component *
|
||
-stream_find_component_by_id (const Stream *stream, guint id);
|
||
+NiceComponent *
|
||
+nice_stream_find_component_by_id (NiceStream *stream, guint id);
|
||
|
||
void
|
||
-stream_initialize_credentials (Stream *stream, NiceRNG *rng);
|
||
+nice_stream_initialize_credentials (NiceStream *stream, NiceRNG *rng);
|
||
|
||
void
|
||
-stream_restart (NiceAgent *agent, Stream *stream);
|
||
+nice_stream_restart (NiceStream *stream, NiceAgent *agent);
|
||
|
||
G_END_DECLS
|
||
|
||
diff --git a/autogen.sh b/autogen.sh
|
||
index 2f58146..b6efba6 100755
|
||
--- a/autogen.sh
|
||
+++ b/autogen.sh
|
||
@@ -1,27 +1,38 @@
|
||
#!/bin/sh
|
||
-set -e
|
||
-
|
||
-test -d m4 || mkdir m4
|
||
-gtkdocize || exit 1
|
||
-
|
||
-autoreconf -fi
|
||
-
|
||
-# Honor NOCONFIGURE for compatibility with gnome-autogen.sh
|
||
-if test x"$NOCONFIGURE" = x; then
|
||
- run_configure=true
|
||
- for arg in $*; do
|
||
- case $arg in
|
||
- --no-configure)
|
||
- run_configure=false
|
||
- ;;
|
||
- *)
|
||
- ;;
|
||
- esac
|
||
- done
|
||
-else
|
||
- run_configure=false
|
||
+# Run this to generate all the initial makefiles, etc.
|
||
+test -n "$srcdir" || srcdir=$(dirname "$0")
|
||
+test -n "$srcdir" || srcdir=.
|
||
+
|
||
+olddir=$(pwd)
|
||
+
|
||
+cd $srcdir
|
||
+
|
||
+(test -f configure.ac) || {
|
||
+ echo "*** ERROR: Directory '$srcdir' does not look like the top-level project directory ***"
|
||
+ exit 1
|
||
+}
|
||
+
|
||
+# shellcheck disable=SC2016
|
||
+PKG_NAME=$(autoconf --trace 'AC_INIT:$1' configure.ac)
|
||
+
|
||
+if [ "$#" = 0 -a "x$NOCONFIGURE" = "x" ]; then
|
||
+ echo "*** WARNING: I am going to run 'configure' with no arguments." >&2
|
||
+ echo "*** If you wish to pass any to it, please specify them on the" >&2
|
||
+ echo "*** '$0' command line." >&2
|
||
+ echo "" >&2
|
||
fi
|
||
|
||
-if test $run_configure = true; then
|
||
- ./configure "$@"
|
||
+aclocal --install || exit 1
|
||
+gtkdocize --copy || exit 1
|
||
+autoreconf --verbose --force --install || exit 1
|
||
+
|
||
+cd "$olddir"
|
||
+if [ "$NOCONFIGURE" = "" ]; then
|
||
+ $srcdir/configure "$@" || exit 1
|
||
+
|
||
+ if [ "$1" = "--help" ]; then exit 0 else
|
||
+ echo "Now type 'make' to compile $PKG_NAME" || exit 1
|
||
+ fi
|
||
+else
|
||
+ echo "Skipping configure process."
|
||
fi
|
||
diff --git a/configure.ac b/configure.ac
|
||
index 6031cec..6be4010 100644
|
||
--- a/configure.ac
|
||
+++ b/configure.ac
|
||
@@ -93,9 +93,9 @@ AC_CHECK_HEADERS([ifaddrs.h], \
|
||
AC_CHECK_TYPES([size_t, ssize_t])
|
||
|
||
# Also put matching version in LIBNICE_CFLAGS
|
||
-GLIB_REQ=2.30
|
||
+GLIB_REQ=2.44
|
||
|
||
-LIBNICE_CFLAGS="-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_30 -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_36"
|
||
+LIBNICE_CFLAGS="-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_44 -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_44"
|
||
|
||
dnl Support different levels of compiler error reporting.
|
||
dnl This configure flag is designed to mimic one from gnome-common,
|
||
@@ -231,9 +231,6 @@ AS_IF([test "$with_gstreamer" != no], [
|
||
[
|
||
have_gst_check=no
|
||
])
|
||
-
|
||
- AM_CONDITIONAL(HAVE_GST_CHECK, test "$have_gst_check" = yes)
|
||
-
|
||
])
|
||
|
||
AS_IF([test "$with_gstreamer010" != no], [
|
||
@@ -260,6 +257,7 @@ AC_SUBST(gstplugindir)
|
||
AC_SUBST(gstplugin010dir)
|
||
|
||
AM_CONDITIONAL(WITH_GSTREAMER, test "$with_gstreamer" = yes)
|
||
+AM_CONDITIONAL(HAVE_GST_CHECK, test "$have_gst_check" = yes)
|
||
AM_CONDITIONAL(WITH_GSTREAMER010, test "$with_gstreamer010" = yes)
|
||
|
||
GUPNP_IGD_REQUIRED=0.2.4
|
||
diff --git a/docs/design.txt b/docs/design.txt
|
||
index 4f43724..6a3bf12 100644
|
||
--- a/docs/design.txt
|
||
+++ b/docs/design.txt
|
||
@@ -90,7 +90,6 @@ NiceAgent GObject interface defined in 'nice/agent.h'.
|
||
|
||
The rough order of control follow is as follows:
|
||
|
||
-- client should initialize glib with g_type_init()
|
||
- creation of NiceAgent object instance
|
||
- setting agent properties such as STUN and TURN server addresses
|
||
- connecting the GObject signals with g_signal_connect() to application
|
||
diff --git a/docs/reference/libnice/Makefile.am b/docs/reference/libnice/Makefile.am
|
||
index 1d53e3b..19e479e 100644
|
||
--- a/docs/reference/libnice/Makefile.am
|
||
+++ b/docs/reference/libnice/Makefile.am
|
||
@@ -62,7 +62,7 @@ IGNORE_HFILES= conncheck.h discovery.h stream.h component.h agent-priv.h \
|
||
|
||
# Images to copy into HTML directory.
|
||
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
|
||
-HTML_IMAGES=
|
||
+HTML_IMAGES = states.png
|
||
|
||
# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
|
||
# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
|
||
@@ -94,13 +94,19 @@ include $(top_srcdir)/gtk-doc.make
|
||
|
||
# Other files to distribute
|
||
# e.g. EXTRA_DIST += version.xml.in
|
||
-#EXTRA_DIST +=
|
||
+EXTRA_DIST += states.gv
|
||
|
||
# Files not to distribute
|
||
# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
|
||
# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
|
||
#DISTCLEANFILES +=
|
||
|
||
+# If we ever need to regenerate this diagram.
|
||
+# Since it’s not expected to change much, let’s not depend on GraphViz to
|
||
+# build the docs.
|
||
+states.png: states.gv
|
||
+ dot -Tpng -Gsize=9.6,2.9\! -Gdpi=200 $^ > $@
|
||
+
|
||
if ENABLE_GTK_DOC
|
||
TESTS_ENVIRONMENT = cd $(builddir) &&
|
||
TESTS = $(GTKDOC_CHECK)
|
||
diff --git a/docs/reference/libnice/states.gv b/docs/reference/libnice/states.gv
|
||
new file mode 100644
|
||
index 0000000..609be2e
|
||
--- /dev/null
|
||
+++ b/docs/reference/libnice/states.gv
|
||
@@ -0,0 +1,25 @@
|
||
+/* libnice state transition diagram for NiceComponentState. */
|
||
+digraph NiceComponentState {
|
||
+ rankdir=TB;
|
||
+ node [shape = doublecircle]; DISCONNECTED;
|
||
+ node [shape = circle];
|
||
+
|
||
+ /* Colour the normal control flow in green. */
|
||
+ DISCONNECTED -> GATHERING [ label = "nice_agent_gather_candidates()", color = chartreuse3 ];
|
||
+ GATHERING -> CONNECTING [ label = "nice_agent_set_remote_candidates()", color = chartreuse3 ];
|
||
+ CONNECTING -> CONNECTED [ label = "At least one candidate pair succeeds", color = chartreuse3 ];
|
||
+ CONNECTED -> READY [ label = "All candidate pairs checks finished", color = chartreuse3 ];
|
||
+
|
||
+ READY -> CONNECTED [ label = "Selected candidate pair fails" ];
|
||
+
|
||
+ FAILED -> CONNECTING [ label = "nice_agent_set_remote_candidates()" ];
|
||
+
|
||
+ DISCONNECTED -> CONNECTING [ label = "nice_agent_set_remote_candidates()" ];
|
||
+
|
||
+ /* Colour the failure paths in grey. */
|
||
+ DISCONNECTED -> FAILED [ label = "Failure", color = gray ];
|
||
+ GATHERING -> FAILED [ label = "Failure", color = gray ];
|
||
+ CONNECTING -> FAILED [ label = "Failure", color = gray ];
|
||
+ CONNECTED -> FAILED [ label = "Failure", color = gray ];
|
||
+ READY -> FAILED [ label = "Failure", color = gray ];
|
||
+}
|
||
diff --git a/docs/reference/libnice/states.png b/docs/reference/libnice/states.png
|
||
new file mode 100644
|
||
index 0000000..ba23739
|
||
Binary files /dev/null and b/docs/reference/libnice/states.png differ
|
||
diff --git a/examples/sdp-example.c b/examples/sdp-example.c
|
||
index 246341e..b6dd80a 100644
|
||
--- a/examples/sdp-example.c
|
||
+++ b/examples/sdp-example.c
|
||
@@ -44,9 +44,7 @@
|
||
|
||
#include <agent.h>
|
||
|
||
-#if GLIB_CHECK_VERSION(2, 36, 0)
|
||
#include <gio/gnetworking.h>
|
||
-#endif
|
||
|
||
static GMainLoop *gloop;
|
||
static gchar *stun_addr = NULL;
|
||
@@ -95,11 +93,7 @@ main(int argc, char *argv[])
|
||
g_debug("Using stun server '[%s]:%u'\n", stun_addr, stun_port);
|
||
}
|
||
|
||
-#if GLIB_CHECK_VERSION(2, 36, 0)
|
||
g_networking_init();
|
||
-#else
|
||
- g_type_init();
|
||
-#endif
|
||
|
||
gloop = g_main_loop_new(NULL, FALSE);
|
||
|
||
diff --git a/examples/simple-example.c b/examples/simple-example.c
|
||
index 6e13dc6..a511d29 100644
|
||
--- a/examples/simple-example.c
|
||
+++ b/examples/simple-example.c
|
||
@@ -44,9 +44,7 @@
|
||
|
||
#include <agent.h>
|
||
|
||
-#if GLIB_CHECK_VERSION(2, 36, 0)
|
||
#include <gio/gnetworking.h>
|
||
-#endif
|
||
|
||
static GMainLoop *gloop;
|
||
static GIOChannel* io_stdin;
|
||
@@ -105,11 +103,7 @@ main(int argc, char *argv[])
|
||
g_debug("Using stun server '[%s]:%u'\n", stun_addr, stun_port);
|
||
}
|
||
|
||
-#if GLIB_CHECK_VERSION(2, 36, 0)
|
||
g_networking_init();
|
||
-#else
|
||
- g_type_init();
|
||
-#endif
|
||
|
||
gloop = g_main_loop_new(NULL, FALSE);
|
||
#ifdef G_OS_WIN32
|
||
@@ -226,7 +220,7 @@ cb_component_state_changed(NiceAgent *agent, guint _stream_id,
|
||
g_debug("SIGNAL: state changed %d %d %s[%d]\n",
|
||
_stream_id, component_id, state_name[state], state);
|
||
|
||
- if (state == NICE_COMPONENT_STATE_READY) {
|
||
+ if (state == NICE_COMPONENT_STATE_CONNECTED) {
|
||
NiceCandidate *local, *remote;
|
||
|
||
// Get current selected candidate pair and print IP address used
|
||
diff --git a/examples/threaded-example.c b/examples/threaded-example.c
|
||
index 79eda8d..575b4dc 100644
|
||
--- a/examples/threaded-example.c
|
||
+++ b/examples/threaded-example.c
|
||
@@ -44,9 +44,7 @@
|
||
|
||
#include <agent.h>
|
||
|
||
-#if GLIB_CHECK_VERSION(2, 36, 0)
|
||
#include <gio/gnetworking.h>
|
||
-#endif
|
||
|
||
static GMainLoop *gloop;
|
||
static gchar *stun_addr = NULL;
|
||
@@ -104,11 +102,6 @@ main(int argc, char *argv[])
|
||
g_debug("Using stun server '[%s]:%u'\n", stun_addr, stun_port);
|
||
}
|
||
|
||
-#if GLIB_CHECK_VERSION(2, 36, 0)
|
||
- g_networking_init();
|
||
-#else
|
||
- g_type_init();
|
||
-#endif
|
||
g_networking_init();
|
||
|
||
gloop = g_main_loop_new(NULL, FALSE);
|
||
diff --git a/nice/libnice.sym b/nice/libnice.sym
|
||
index efcfdc3..b04bb95 100644
|
||
--- a/nice/libnice.sym
|
||
+++ b/nice/libnice.sym
|
||
@@ -74,12 +74,16 @@ pseudo_tcp_socket_close
|
||
pseudo_tcp_socket_connect
|
||
pseudo_tcp_socket_get_error
|
||
pseudo_tcp_socket_get_next_clock
|
||
+pseudo_tcp_socket_get_type
|
||
+pseudo_tcp_socket_is_closed
|
||
+pseudo_tcp_socket_is_closed_remotely
|
||
pseudo_tcp_socket_new
|
||
pseudo_tcp_socket_notify_clock
|
||
pseudo_tcp_socket_notify_mtu
|
||
pseudo_tcp_socket_notify_packet
|
||
pseudo_tcp_socket_recv
|
||
pseudo_tcp_socket_send
|
||
+pseudo_tcp_socket_shutdown
|
||
stun_agent_build_unknown_attributes_error
|
||
stun_agent_default_validater
|
||
stun_agent_finish_message
|
||
diff --git a/socket/http.c b/socket/http.c
|
||
index 404d378..96ddfd8 100644
|
||
--- a/socket/http.c
|
||
+++ b/socket/http.c
|
||
@@ -95,6 +95,7 @@ static gboolean socket_is_reliable (NiceSocket *sock);
|
||
static gboolean socket_can_send (NiceSocket *sock, NiceAddress *addr);
|
||
static void socket_set_writable_callback (NiceSocket *sock,
|
||
NiceSocketWritableCb callback, gpointer user_data);
|
||
+static gboolean socket_is_based_on (NiceSocket *sock, NiceSocket *other);
|
||
|
||
NiceSocket *
|
||
nice_http_socket_new (NiceSocket *base_socket,
|
||
@@ -126,6 +127,7 @@ nice_http_socket_new (NiceSocket *base_socket,
|
||
sock->is_reliable = socket_is_reliable;
|
||
sock->can_send = socket_can_send;
|
||
sock->set_writable_callback = socket_set_writable_callback;
|
||
+ sock->is_based_on = socket_is_based_on;
|
||
sock->close = socket_close;
|
||
|
||
/* Send HTTP CONNECT */
|
||
@@ -281,9 +283,8 @@ socket_recv_messages (NiceSocket *sock,
|
||
HttpPriv *priv = sock->priv;
|
||
gint ret = -1;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (sock->priv == NULL)
|
||
- return 0;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (sock->priv != NULL);
|
||
|
||
if (priv->state == HTTP_STATE_CONNECTED) {
|
||
guint i;
|
||
@@ -576,9 +577,8 @@ socket_send_messages (NiceSocket *sock, const NiceAddress *to,
|
||
{
|
||
HttpPriv *priv = sock->priv;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (sock->priv == NULL)
|
||
- return -1;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (sock->priv != NULL);
|
||
|
||
if (priv->state == HTTP_STATE_CONNECTED) {
|
||
/* Fast path. */
|
||
@@ -642,3 +642,12 @@ socket_set_writable_callback (NiceSocket *sock,
|
||
|
||
nice_socket_set_writable_callback (priv->base_socket, callback, user_data);
|
||
}
|
||
+
|
||
+static gboolean
|
||
+socket_is_based_on (NiceSocket *sock, NiceSocket *other)
|
||
+{
|
||
+ HttpPriv *priv = sock->priv;
|
||
+
|
||
+ return (sock == other) ||
|
||
+ (priv && nice_socket_is_based_on (priv->base_socket, other));
|
||
+}
|
||
diff --git a/socket/pseudossl.c b/socket/pseudossl.c
|
||
index 5ad4f97..052725c 100644
|
||
--- a/socket/pseudossl.c
|
||
+++ b/socket/pseudossl.c
|
||
@@ -116,6 +116,7 @@ static gboolean socket_is_reliable (NiceSocket *sock);
|
||
static gboolean socket_can_send (NiceSocket *sock, NiceAddress *addr);
|
||
static void socket_set_writable_callback (NiceSocket *sock,
|
||
NiceSocketWritableCb callback, gpointer user_data);
|
||
+static gboolean socket_is_based_on (NiceSocket *sock, NiceSocket *other);
|
||
|
||
NiceSocket *
|
||
nice_pseudossl_socket_new (NiceSocket *base_socket,
|
||
@@ -152,6 +153,7 @@ nice_pseudossl_socket_new (NiceSocket *base_socket,
|
||
sock->is_reliable = socket_is_reliable;
|
||
sock->can_send = socket_can_send;
|
||
sock->set_writable_callback = socket_set_writable_callback;
|
||
+ sock->is_based_on = socket_is_based_on;
|
||
sock->close = socket_close;
|
||
|
||
/* We send 'to' NULL because it will always be to an already connected
|
||
@@ -204,9 +206,8 @@ socket_recv_messages (NiceSocket *sock,
|
||
{
|
||
PseudoSSLPriv *priv = sock->priv;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (sock->priv == NULL)
|
||
- return 0;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (sock->priv != NULL);
|
||
|
||
if (priv->handshaken) {
|
||
if (priv->base_socket) {
|
||
@@ -256,9 +257,8 @@ socket_send_messages (NiceSocket *sock, const NiceAddress *to,
|
||
{
|
||
PseudoSSLPriv *priv = sock->priv;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (sock->priv == NULL)
|
||
- return -1;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (sock->priv != NULL);
|
||
|
||
if (priv->handshaken) {
|
||
/* Fast path: pass directly through to the base socket once the handshake is
|
||
@@ -319,3 +319,12 @@ socket_set_writable_callback (NiceSocket *sock,
|
||
|
||
nice_socket_set_writable_callback (priv->base_socket, callback, user_data);
|
||
}
|
||
+
|
||
+static gboolean
|
||
+socket_is_based_on (NiceSocket *sock, NiceSocket *other)
|
||
+{
|
||
+ PseudoSSLPriv *priv = sock->priv;
|
||
+
|
||
+ return (sock == other) ||
|
||
+ (priv && nice_socket_is_based_on (priv->base_socket, other));
|
||
+}
|
||
diff --git a/socket/socket.c b/socket/socket.c
|
||
index 9c0d978..08ae31a 100644
|
||
--- a/socket/socket.c
|
||
+++ b/socket/socket.c
|
||
@@ -265,6 +265,14 @@ nice_socket_set_writable_callback (NiceSocket *sock,
|
||
sock->set_writable_callback (sock, callback, user_data);
|
||
}
|
||
|
||
+gboolean
|
||
+nice_socket_is_based_on (NiceSocket *sock, NiceSocket *other)
|
||
+{
|
||
+ if (sock->is_based_on)
|
||
+ return sock->is_based_on (sock, other);
|
||
+ return (sock == other);
|
||
+}
|
||
+
|
||
void
|
||
nice_socket_free (NiceSocket *sock)
|
||
{
|
||
diff --git a/socket/socket.h b/socket/socket.h
|
||
index 41ea07b..fadcbc1 100644
|
||
--- a/socket/socket.h
|
||
+++ b/socket/socket.h
|
||
@@ -88,6 +88,7 @@ struct _NiceSocket
|
||
gboolean (*can_send) (NiceSocket *sock, NiceAddress *addr);
|
||
void (*set_writable_callback) (NiceSocket *sock,
|
||
NiceSocketWritableCb callback, gpointer user_data);
|
||
+ gboolean (*is_based_on) (NiceSocket *sock, NiceSocket *other);
|
||
void (*close) (NiceSocket *sock);
|
||
void *priv;
|
||
};
|
||
@@ -124,6 +125,23 @@ void
|
||
nice_socket_set_writable_callback (NiceSocket *sock,
|
||
NiceSocketWritableCb callback, gpointer user_data);
|
||
|
||
+/**
|
||
+ * nice_socket_is_based_on:
|
||
+ * @sock: a #NiceSocket
|
||
+ * @other: another #NiceSocket
|
||
+ *
|
||
+ * Checks whether @sock wraps @other as a source and destination of its read and
|
||
+ * write operations. The function traverses the whole chain of @sock's base
|
||
+ * sockets until @other is found or the end is reached.
|
||
+ *
|
||
+ * Returns: %TRUE if @sock is based on @other or if @sock and @other are
|
||
+ * the same socket, %FALSE otherwise.
|
||
+ *
|
||
+ * Since: UNRELEASED
|
||
+ */
|
||
+gboolean
|
||
+nice_socket_is_based_on (NiceSocket *sock, NiceSocket *other);
|
||
+
|
||
void
|
||
nice_socket_free (NiceSocket *sock);
|
||
|
||
diff --git a/socket/socks5.c b/socket/socks5.c
|
||
index 46d17fb..d15fc29 100644
|
||
--- a/socket/socks5.c
|
||
+++ b/socket/socks5.c
|
||
@@ -81,6 +81,7 @@ static gboolean socket_is_reliable (NiceSocket *sock);
|
||
static gboolean socket_can_send (NiceSocket *sock, NiceAddress *addr);
|
||
static void socket_set_writable_callback (NiceSocket *sock,
|
||
NiceSocketWritableCb callback, gpointer user_data);
|
||
+static gboolean socket_is_based_on (NiceSocket *sock, NiceSocket *other);
|
||
|
||
|
||
NiceSocket *
|
||
@@ -108,6 +109,7 @@ nice_socks5_socket_new (NiceSocket *base_socket,
|
||
sock->is_reliable = socket_is_reliable;
|
||
sock->can_send = socket_can_send;
|
||
sock->set_writable_callback = socket_set_writable_callback;
|
||
+ sock->is_based_on = socket_is_based_on;
|
||
sock->close = socket_close;
|
||
|
||
/* Send SOCKS5 handshake */
|
||
@@ -167,9 +169,8 @@ socket_recv_messages (NiceSocket *sock,
|
||
guint i;
|
||
gint ret = -1;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (sock->priv == NULL)
|
||
- return 0;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (sock->priv != NULL);
|
||
|
||
switch (priv->state) {
|
||
case SOCKS_STATE_CONNECTED:
|
||
@@ -423,9 +424,8 @@ socket_send_messages (NiceSocket *sock, const NiceAddress *to,
|
||
{
|
||
Socks5Priv *priv = sock->priv;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (sock->priv == NULL)
|
||
- return -1;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (sock->priv != NULL);
|
||
|
||
if (priv->state == SOCKS_STATE_CONNECTED) {
|
||
/* Fast path: pass through to the base socket once connected. */
|
||
@@ -488,3 +488,12 @@ socket_set_writable_callback (NiceSocket *sock,
|
||
|
||
nice_socket_set_writable_callback (priv->base_socket, callback, user_data);
|
||
}
|
||
+
|
||
+static gboolean
|
||
+socket_is_based_on (NiceSocket *sock, NiceSocket *other)
|
||
+{
|
||
+ Socks5Priv *priv = sock->priv;
|
||
+
|
||
+ return (sock == other) ||
|
||
+ (priv && nice_socket_is_based_on (priv->base_socket, other));
|
||
+}
|
||
diff --git a/socket/tcp-active.c b/socket/tcp-active.c
|
||
index 5144678..5402806 100644
|
||
--- a/socket/tcp-active.c
|
||
+++ b/socket/tcp-active.c
|
||
@@ -50,6 +50,11 @@
|
||
#include <unistd.h>
|
||
#endif
|
||
|
||
+/* FIXME: This should be defined in gio/gnetworking.h, which we should include;
|
||
+ * but we cannot do that without refactoring.
|
||
+ * (See: https://phabricator.freedesktop.org/D230). */
|
||
+#define TCP_NODELAY 1
|
||
+
|
||
typedef struct {
|
||
GSocketAddress *local_addr;
|
||
GMainContext *context;
|
||
@@ -225,6 +230,9 @@ nice_tcp_active_socket_connect (NiceSocket *sock, NiceAddress *addr)
|
||
/* GSocket: All socket file descriptors are set to be close-on-exec. */
|
||
g_socket_set_blocking (gsock, false);
|
||
|
||
+ /* setting TCP_NODELAY to TRUE in order to avoid packet batching */
|
||
+ g_socket_set_option (gsock, IPPROTO_TCP, TCP_NODELAY, TRUE, NULL);
|
||
+
|
||
/* Allow g_socket_bind to fail */
|
||
g_socket_bind (gsock, priv->local_addr, FALSE, NULL);
|
||
|
||
diff --git a/socket/tcp-bsd.c b/socket/tcp-bsd.c
|
||
index 20dd698..3e5f5a8 100644
|
||
--- a/socket/tcp-bsd.c
|
||
+++ b/socket/tcp-bsd.c
|
||
@@ -54,6 +54,11 @@
|
||
#include <unistd.h>
|
||
#endif
|
||
|
||
+/* FIXME: This should be defined in gio/gnetworking.h, which we should include;
|
||
+ * but we cannot do that without refactoring.
|
||
+ * (See: https://phabricator.freedesktop.org/D230). */
|
||
+#define TCP_NODELAY 1
|
||
+
|
||
typedef struct {
|
||
NiceAddress remote_addr;
|
||
GQueue send_queue;
|
||
@@ -168,6 +173,9 @@ nice_tcp_bsd_socket_new (GMainContext *ctx, NiceAddress *local_addr,
|
||
/* GSocket: All socket file descriptors are set to be close-on-exec. */
|
||
g_socket_set_blocking (gsock, false);
|
||
|
||
+ /* setting TCP_NODELAY to TRUE in order to avoid packet batching */
|
||
+ g_socket_set_option (gsock, IPPROTO_TCP, TCP_NODELAY, TRUE, NULL);
|
||
+
|
||
gret = g_socket_connect (gsock, gaddr, NULL, &gerr);
|
||
g_object_unref (gaddr);
|
||
|
||
@@ -229,9 +237,8 @@ socket_recv_messages (NiceSocket *sock,
|
||
TcpPriv *priv = sock->priv;
|
||
guint i;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (sock->priv == NULL)
|
||
- return 0;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (sock->priv != NULL);
|
||
|
||
/* Don't try to access the socket if it had an error */
|
||
if (priv->error)
|
||
@@ -283,9 +290,8 @@ socket_send_message (NiceSocket *sock,
|
||
GError *gerr = NULL;
|
||
gsize message_len;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (sock->priv == NULL)
|
||
- return -1;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (sock->priv != NULL);
|
||
|
||
/* Don't try to access the socket if it had an error, otherwise we risk a
|
||
* crash with SIGPIPE (Broken pipe) */
|
||
@@ -344,9 +350,8 @@ socket_send_messages (NiceSocket *sock, const NiceAddress *to,
|
||
{
|
||
guint i;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (sock->priv == NULL)
|
||
- return -1;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (sock->priv != NULL);
|
||
|
||
for (i = 0; i < n_messages; i++) {
|
||
const NiceOutputMessage *message = &messages[i];
|
||
diff --git a/socket/tcp-passive.c b/socket/tcp-passive.c
|
||
index 30bfba8..131ff4b 100644
|
||
--- a/socket/tcp-passive.c
|
||
+++ b/socket/tcp-passive.c
|
||
@@ -50,6 +50,11 @@
|
||
#include <unistd.h>
|
||
#endif
|
||
|
||
+/* FIXME: This should be defined in gio/gnetworking.h, which we should include;
|
||
+ * but we cannot do that without refactoring.
|
||
+ * (See: https://phabricator.freedesktop.org/D230). */
|
||
+#define TCP_NODELAY 1
|
||
+
|
||
typedef struct {
|
||
GMainContext *context;
|
||
GHashTable *connections;
|
||
@@ -176,6 +181,12 @@ socket_close (NiceSocket *sock)
|
||
{
|
||
TcpPassivePriv *priv = sock->priv;
|
||
|
||
+ if (sock->fileno != NULL) {
|
||
+ g_socket_close (sock->fileno, NULL);
|
||
+ g_object_unref (sock->fileno);
|
||
+ sock->fileno = NULL;
|
||
+ }
|
||
+
|
||
if (priv->context)
|
||
g_main_context_unref (priv->context);
|
||
g_hash_table_unref (priv->connections);
|
||
@@ -278,6 +289,9 @@ nice_tcp_passive_socket_accept (NiceSocket *sock)
|
||
/* GSocket: All socket file descriptors are set to be close-on-exec. */
|
||
g_socket_set_blocking (gsock, false);
|
||
|
||
+ /* setting TCP_NODELAY to TRUE in order to avoid packet batching */
|
||
+ g_socket_set_option (gsock, IPPROTO_TCP, TCP_NODELAY, TRUE, NULL);
|
||
+
|
||
gaddr = g_socket_get_remote_address (gsock, NULL);
|
||
if (gaddr == NULL ||
|
||
!g_socket_address_to_native (gaddr, &name.addr, sizeof (name), NULL)) {
|
||
diff --git a/socket/udp-bsd.c b/socket/udp-bsd.c
|
||
index d56f093..3fac544 100644
|
||
--- a/socket/udp-bsd.c
|
||
+++ b/socket/udp-bsd.c
|
||
@@ -183,9 +183,8 @@ socket_recv_messages (NiceSocket *sock,
|
||
guint i;
|
||
gboolean error = FALSE;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (sock->priv == NULL)
|
||
- return 0;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (sock->priv != NULL);
|
||
|
||
/* Read messages into recv_messages until one fails or would block, or we
|
||
* reach the end. */
|
||
@@ -204,7 +203,10 @@ socket_recv_messages (NiceSocket *sock,
|
||
recv_message->length = MAX (recvd, 0);
|
||
|
||
if (recvd < 0) {
|
||
- if (g_error_matches (gerr, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
|
||
+ /* Handle ECONNRESET here as if it were EWOULDBLOCK; see
|
||
+ * https://phabricator.freedesktop.org/T121 */
|
||
+ if (g_error_matches (gerr, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) ||
|
||
+ g_error_matches (gerr, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
|
||
recvd = 0;
|
||
else
|
||
error = TRUE;
|
||
@@ -245,9 +247,8 @@ socket_send_message (NiceSocket *sock, const NiceAddress *to,
|
||
GError *child_error = NULL;
|
||
gssize len;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (priv == NULL)
|
||
- return -1;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (sock->priv != NULL);
|
||
|
||
if (!nice_address_is_valid (&priv->niceaddr) ||
|
||
!nice_address_equal (&priv->niceaddr, to)) {
|
||
@@ -289,9 +290,8 @@ socket_send_messages (NiceSocket *sock, const NiceAddress *to,
|
||
{
|
||
guint i;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (sock->priv == NULL)
|
||
- return -1;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (sock->priv != NULL);
|
||
|
||
for (i = 0; i < n_messages; i++) {
|
||
const NiceOutputMessage *message = &messages[i];
|
||
diff --git a/socket/udp-turn-over-tcp.c b/socket/udp-turn-over-tcp.c
|
||
index d97fa04..2b91f92 100644
|
||
--- a/socket/udp-turn-over-tcp.c
|
||
+++ b/socket/udp-turn-over-tcp.c
|
||
@@ -86,6 +86,7 @@ static gboolean socket_is_reliable (NiceSocket *sock);
|
||
static gboolean socket_can_send (NiceSocket *sock, NiceAddress *addr);
|
||
static void socket_set_writable_callback (NiceSocket *sock,
|
||
NiceSocketWritableCb callback, gpointer user_data);
|
||
+static gboolean socket_is_based_on (NiceSocket *sock, NiceSocket *other);
|
||
|
||
NiceSocket *
|
||
nice_udp_turn_over_tcp_socket_new (NiceSocket *base_socket,
|
||
@@ -107,6 +108,7 @@ nice_udp_turn_over_tcp_socket_new (NiceSocket *base_socket,
|
||
sock->is_reliable = socket_is_reliable;
|
||
sock->can_send = socket_can_send;
|
||
sock->set_writable_callback = socket_set_writable_callback;
|
||
+ sock->is_based_on = socket_is_based_on;
|
||
sock->close = socket_close;
|
||
|
||
return sock;
|
||
@@ -134,9 +136,8 @@ socket_recv_message (NiceSocket *sock, NiceInputMessage *recv_message)
|
||
GInputVector local_recv_buf;
|
||
NiceInputMessage local_recv_message;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (sock->priv == NULL)
|
||
- return 0;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (sock->priv != NULL);
|
||
|
||
if (priv->expecting_len == 0) {
|
||
guint headerlen = 0;
|
||
@@ -241,9 +242,8 @@ socket_recv_messages (NiceSocket *nicesock,
|
||
guint i;
|
||
gboolean error = FALSE;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (nicesock->priv == NULL)
|
||
- return 0;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (nicesock->priv != NULL);
|
||
|
||
for (i = 0; i < n_recv_messages; i++) {
|
||
gssize len;
|
||
@@ -285,9 +285,8 @@ socket_send_message (NiceSocket *sock, const NiceAddress *to,
|
||
} header_buf;
|
||
guint offset = 0;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (sock->priv == NULL)
|
||
- return -1;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (sock->priv != NULL);
|
||
|
||
/* Count the number of buffers. */
|
||
if (message->n_buffers == -1) {
|
||
@@ -301,7 +300,7 @@ socket_send_message (NiceSocket *sock, const NiceAddress *to,
|
||
|
||
/* Allocate a new array of buffers, covering all the buffers in the input
|
||
* @message, but with an additional one for a header and one for a footer. */
|
||
- local_bufs = g_malloc_n (n_bufs + 1, sizeof (GOutputVector));
|
||
+ local_bufs = g_alloca ((n_bufs + 1) * sizeof (GOutputVector));
|
||
local_message.buffers = local_bufs;
|
||
local_message.n_buffers = n_bufs + 1;
|
||
|
||
@@ -377,8 +376,6 @@ socket_send_message (NiceSocket *sock, const NiceAddress *to,
|
||
if (ret == 1)
|
||
ret = output_message_get_size (&local_message);
|
||
|
||
- g_free (local_bufs);
|
||
-
|
||
return ret;
|
||
}
|
||
|
||
@@ -388,9 +385,8 @@ socket_send_messages (NiceSocket *sock, const NiceAddress *to,
|
||
{
|
||
guint i;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (sock->priv == NULL)
|
||
- return -1;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (sock->priv != NULL);
|
||
|
||
for (i = 0; i < n_messages; i++) {
|
||
const NiceOutputMessage *message = &messages[i];
|
||
@@ -458,3 +454,12 @@ socket_set_writable_callback (NiceSocket *sock,
|
||
|
||
nice_socket_set_writable_callback (priv->base_socket, callback, user_data);
|
||
}
|
||
+
|
||
+static gboolean
|
||
+socket_is_based_on (NiceSocket *sock, NiceSocket *other)
|
||
+{
|
||
+ TurnTcpPriv *priv = sock->priv;
|
||
+
|
||
+ return (sock == other) ||
|
||
+ (priv && nice_socket_is_based_on (priv->base_socket, other));
|
||
+}
|
||
diff --git a/socket/udp-turn.c b/socket/udp-turn.c
|
||
index e640363..617e4f3 100644
|
||
--- a/socket/udp-turn.c
|
||
+++ b/socket/udp-turn.c
|
||
@@ -98,6 +98,11 @@ typedef struct {
|
||
GHashTable *send_data_queues; /* stores a send data queue for per peer */
|
||
GSource *permission_timeout_source; /* timer used to invalidate
|
||
permissions */
|
||
+
|
||
+ guint8 *cached_realm;
|
||
+ uint16_t cached_realm_len;
|
||
+ guint8 *cached_nonce;
|
||
+ uint16_t cached_nonce_len;
|
||
} UdpTurnPriv;
|
||
|
||
|
||
@@ -125,15 +130,16 @@ static gboolean socket_is_reliable (NiceSocket *sock);
|
||
static gboolean socket_can_send (NiceSocket *sock, NiceAddress *addr);
|
||
static void socket_set_writable_callback (NiceSocket *sock,
|
||
NiceSocketWritableCb callback, gpointer user_data);
|
||
+static gboolean socket_is_based_on (NiceSocket *sock, NiceSocket *other);
|
||
|
||
static void priv_process_pending_bindings (UdpTurnPriv *priv);
|
||
static gboolean priv_retransmissions_tick_unlocked (UdpTurnPriv *priv);
|
||
static gboolean priv_retransmissions_tick (gpointer pointer);
|
||
static void priv_schedule_tick (UdpTurnPriv *priv);
|
||
static void priv_send_turn_message (UdpTurnPriv *priv, TURNMessage *msg);
|
||
-static gboolean priv_send_create_permission (UdpTurnPriv *priv, StunMessage *resp,
|
||
+static gboolean priv_send_create_permission (UdpTurnPriv *priv,
|
||
const NiceAddress *peer);
|
||
-static gboolean priv_send_channel_bind (UdpTurnPriv *priv, StunMessage *resp,
|
||
+static gboolean priv_send_channel_bind (UdpTurnPriv *priv,
|
||
uint16_t channel,
|
||
const NiceAddress *peer);
|
||
static gboolean priv_add_channel_binding (UdpTurnPriv *priv,
|
||
@@ -235,7 +241,7 @@ nice_udp_turn_socket_new (GMainContext *ctx, NiceAddress *addr,
|
||
priv_send_data_queue_destroy);
|
||
|
||
sock->type = NICE_SOCKET_TYPE_UDP_TURN;
|
||
- sock->fileno = base_socket->fileno;
|
||
+ sock->fileno = NULL;
|
||
sock->addr = *addr;
|
||
sock->send_messages = socket_send_messages;
|
||
sock->send_messages_reliable = socket_send_messages_reliable;
|
||
@@ -243,6 +249,7 @@ nice_udp_turn_socket_new (GMainContext *ctx, NiceAddress *addr,
|
||
sock->is_reliable = socket_is_reliable;
|
||
sock->can_send = socket_can_send;
|
||
sock->set_writable_callback = socket_set_writable_callback;
|
||
+ sock->is_based_on = socket_is_based_on;
|
||
sock->close = socket_close;
|
||
sock->priv = (void *) priv;
|
||
|
||
@@ -317,6 +324,8 @@ socket_close (NiceSocket *sock)
|
||
g_list_free(priv->pending_permissions);
|
||
g_free (priv->username);
|
||
g_free (priv->password);
|
||
+ g_free (priv->cached_realm);
|
||
+ g_free (priv->cached_nonce);
|
||
g_free (priv);
|
||
|
||
sock->priv = NULL;
|
||
@@ -332,11 +341,10 @@ socket_recv_messages (NiceSocket *sock,
|
||
gboolean error = FALSE;
|
||
guint n_valid_messages;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (sock->priv == NULL)
|
||
- return 0;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (sock->priv != NULL);
|
||
|
||
- nice_debug ("received message on TURN socket");
|
||
+ nice_debug_verbose ("received message on TURN socket");
|
||
|
||
n_messages = nice_socket_recv_messages (priv->base_socket,
|
||
recv_messages, n_recv_messages);
|
||
@@ -374,7 +382,7 @@ socket_recv_messages (NiceSocket *sock,
|
||
buffer = message->buffers[0].buffer;
|
||
buffer_length = message->length;
|
||
} else {
|
||
- nice_debug ("%s: **WARNING: SLOW PATH**", G_STRFUNC);
|
||
+ nice_debug_verbose ("%s: **WARNING: SLOW PATH**", G_STRFUNC);
|
||
|
||
buffer = compact_input_message (message, &buffer_length);
|
||
allocated_buffer = TRUE;
|
||
@@ -575,7 +583,7 @@ _socket_send_messages_wrapped (NiceSocket *sock, const NiceAddress *to,
|
||
n_bufs = message->n_buffers;
|
||
}
|
||
|
||
- local_bufs = g_malloc_n (n_bufs + 1, sizeof (GOutputVector));
|
||
+ local_bufs = g_alloca ((n_bufs + 1) * sizeof (GOutputVector));
|
||
local_message.buffers = local_bufs;
|
||
local_message.n_buffers = n_bufs + 1;
|
||
|
||
@@ -598,8 +606,6 @@ _socket_send_messages_wrapped (NiceSocket *sock, const NiceAddress *to,
|
||
if (ret == 1)
|
||
ret = message_len;
|
||
|
||
- g_free (local_bufs);
|
||
-
|
||
return ret;
|
||
}
|
||
}
|
||
@@ -663,7 +669,7 @@ socket_dequeue_all_data (UdpTurnPriv *priv, const NiceAddress *to)
|
||
SendData *data =
|
||
(SendData *) g_queue_pop_head(send_queue);
|
||
|
||
- nice_debug ("dequeuing data");
|
||
+ nice_debug_verbose ("dequeuing data");
|
||
_socket_send_wrapped (priv->base_socket, &priv->server_addr,
|
||
data->data_len, data->data, data->reliable);
|
||
|
||
@@ -693,9 +699,8 @@ socket_send_message (NiceSocket *sock, const NiceAddress *to,
|
||
ChannelBinding *binding = NULL;
|
||
gint ret;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (sock->priv == NULL)
|
||
- return -1;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (sock->priv != NULL);
|
||
|
||
for (i = priv->channels; i; i = i->next) {
|
||
ChannelBinding *b = i->data;
|
||
@@ -816,7 +821,8 @@ socket_send_message (NiceSocket *sock, const NiceAddress *to,
|
||
/* Finish the message. */
|
||
msg_len = stun_agent_finish_message (&priv->agent, &msg,
|
||
priv->password, priv->password_len);
|
||
- if (msg_len > 0 && stun_message_get_class (&msg) == STUN_REQUEST) {
|
||
+ if (msg_len > 0 && stun_message_get_class (&msg) == STUN_REQUEST &&
|
||
+ priv->compatibility != NICE_TURN_SOCKET_COMPATIBILITY_OC2007) {
|
||
SendRequest *req = g_slice_new0 (SendRequest);
|
||
|
||
req->priv = priv;
|
||
@@ -831,11 +837,11 @@ socket_send_message (NiceSocket *sock, const NiceAddress *to,
|
||
if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766 &&
|
||
!priv_has_permission_for_peer (priv, to)) {
|
||
if (!priv_has_sent_permission_for_peer (priv, to)) {
|
||
- priv_send_create_permission (priv, NULL, to);
|
||
+ priv_send_create_permission (priv, to);
|
||
}
|
||
|
||
/* enque data */
|
||
- nice_debug ("enqueuing data");
|
||
+ nice_debug_verbose ("enqueuing data");
|
||
socket_enqueue_data(priv, to, msg_len, (gchar *)buffer, reliable);
|
||
|
||
return msg_len;
|
||
@@ -868,9 +874,8 @@ socket_send_messages (NiceSocket *sock, const NiceAddress *to,
|
||
{
|
||
guint i;
|
||
|
||
- /* Socket has been closed: */
|
||
- if (sock->priv == NULL)
|
||
- return -1;
|
||
+ /* Make sure socket has not been freed: */
|
||
+ g_assert (sock->priv != NULL);
|
||
|
||
for (i = 0; i < n_messages; i++) {
|
||
const NiceOutputMessage *message = &messages[i];
|
||
@@ -951,6 +956,15 @@ socket_set_writable_callback (NiceSocket *sock,
|
||
}
|
||
|
||
static gboolean
|
||
+socket_is_based_on (NiceSocket *sock, NiceSocket *other)
|
||
+{
|
||
+ UdpTurnPriv *priv = sock->priv;
|
||
+
|
||
+ return (sock == other) ||
|
||
+ (priv && nice_socket_is_based_on (priv->base_socket, other));
|
||
+}
|
||
+
|
||
+static gboolean
|
||
priv_forget_send_request (gpointer pointer)
|
||
{
|
||
SendRequest *req = pointer;
|
||
@@ -1079,13 +1093,20 @@ priv_binding_timeout (gpointer data)
|
||
ChannelBinding *b = i->data;
|
||
if (b->timeout_source == source) {
|
||
b->renew = TRUE;
|
||
+
|
||
+ /* Remove any existing timer */
|
||
+ if (b->timeout_source) {
|
||
+ g_source_destroy (b->timeout_source);
|
||
+ g_source_unref (b->timeout_source);
|
||
+ }
|
||
+
|
||
/* Install timer to expire the permission */
|
||
b->timeout_source = priv_timeout_add_with_context (priv,
|
||
STUN_EXPIRE_TIMEOUT, TRUE, priv_binding_expired_timeout, priv);
|
||
|
||
/* Send renewal */
|
||
if (!priv->current_binding_msg)
|
||
- priv_send_channel_bind (priv, NULL, b->channel, &b->peer);
|
||
+ priv_send_channel_bind (priv, b->channel, &b->peer);
|
||
break;
|
||
}
|
||
}
|
||
@@ -1095,6 +1116,31 @@ priv_binding_timeout (gpointer data)
|
||
return FALSE;
|
||
}
|
||
|
||
+void
|
||
+nice_udp_turn_socket_cache_realm_nonce (NiceSocket *sock, StunMessage *msg)
|
||
+{
|
||
+ UdpTurnPriv *priv = sock->priv;
|
||
+ gconstpointer tmp;
|
||
+
|
||
+ g_assert (sock->type == NICE_SOCKET_TYPE_UDP_TURN);
|
||
+
|
||
+ g_free (priv->cached_realm);
|
||
+ priv->cached_realm = NULL;
|
||
+ priv->cached_realm_len = 0;
|
||
+
|
||
+ g_free (priv->cached_nonce);
|
||
+ priv->cached_nonce = NULL;
|
||
+ priv->cached_nonce_len = 0;
|
||
+
|
||
+ tmp = stun_message_find (msg, STUN_ATTRIBUTE_REALM, &priv->cached_realm_len);
|
||
+ if (tmp && priv->cached_realm_len < 764)
|
||
+ priv->cached_realm = g_memdup (tmp, priv->cached_realm_len);
|
||
+
|
||
+ tmp = stun_message_find (msg, STUN_ATTRIBUTE_NONCE, &priv->cached_nonce_len);
|
||
+ if (tmp && priv->cached_nonce_len < 764)
|
||
+ priv->cached_nonce = g_memdup (tmp, priv->cached_nonce_len);
|
||
+}
|
||
+
|
||
guint
|
||
nice_udp_turn_socket_parse_recv_message (NiceSocket *sock, NiceSocket **from_sock,
|
||
NiceInputMessage *message)
|
||
@@ -1121,7 +1167,7 @@ nice_udp_turn_socket_parse_recv_message (NiceSocket *sock, NiceSocket **from_soc
|
||
}
|
||
|
||
/* Slow path. */
|
||
- nice_debug ("%s: **WARNING: SLOW PATH**", G_STRFUNC);
|
||
+ nice_debug_verbose ("%s: **WARNING: SLOW PATH**", G_STRFUNC);
|
||
|
||
buf = compact_input_message (message, &buf_len);
|
||
len = nice_udp_turn_socket_parse_recv (sock, from_sock,
|
||
@@ -1298,8 +1344,9 @@ nice_udp_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock,
|
||
|
||
g_free (priv->current_binding_msg);
|
||
priv->current_binding_msg = NULL;
|
||
+ nice_udp_turn_socket_cache_realm_nonce (sock, &msg);
|
||
if (binding)
|
||
- priv_send_channel_bind (priv, &msg, binding->channel,
|
||
+ priv_send_channel_bind (priv, binding->channel,
|
||
&binding->peer);
|
||
} else {
|
||
g_free (priv->current_binding);
|
||
@@ -1357,12 +1404,17 @@ nice_udp_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock,
|
||
} peer;
|
||
socklen_t peer_len = sizeof(peer);
|
||
NiceAddress to;
|
||
+ gchar tmpbuf[INET6_ADDRSTRLEN];
|
||
|
||
- nice_debug ("got response for CreatePermission");
|
||
stun_message_find_xor_addr (
|
||
¤t_create_permission_msg->message,
|
||
STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &peer.storage, &peer_len);
|
||
nice_address_set_from_sockaddr (&to, &peer.addr);
|
||
+ nice_address_to_string (&to, tmpbuf);
|
||
+ nice_debug ("TURN: got response for CreatePermission "
|
||
+ "with XOR_PEER_ADDRESS=[%s]:%u : %s",
|
||
+ tmpbuf, nice_address_get_port (&to),
|
||
+ stun_message_get_class (&msg) == STUN_ERROR ? "unauthorized" : "ok");
|
||
|
||
/* unathorized => resend with realm and nonce */
|
||
if (stun_message_get_class (&msg) == STUN_ERROR) {
|
||
@@ -1395,8 +1447,10 @@ nice_udp_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock,
|
||
priv->pending_permissions, i);
|
||
g_free (current_create_permission_msg);
|
||
current_create_permission_msg = NULL;
|
||
+
|
||
+ nice_udp_turn_socket_cache_realm_nonce (sock, &msg);
|
||
/* resend CreatePermission */
|
||
- priv_send_create_permission (priv, &msg, &to);
|
||
+ priv_send_create_permission (priv, &to);
|
||
return 0;
|
||
}
|
||
}
|
||
@@ -1463,7 +1517,7 @@ nice_udp_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock,
|
||
if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766 &&
|
||
!priv_has_permission_for_peer (priv, from)) {
|
||
if (!priv_has_sent_permission_for_peer (priv, from)) {
|
||
- priv_send_create_permission (priv, NULL, from);
|
||
+ priv_send_create_permission (priv, from);
|
||
}
|
||
}
|
||
|
||
@@ -1549,7 +1603,7 @@ priv_process_pending_bindings (UdpTurnPriv *priv)
|
||
for (i = priv->channels ; i; i = i->next) {
|
||
ChannelBinding *b = i->data;
|
||
if (b->renew) {
|
||
- priv_send_channel_bind (priv, NULL, b->channel, &b->peer);
|
||
+ priv_send_channel_bind (priv, b->channel, &b->peer);
|
||
break;
|
||
}
|
||
}
|
||
@@ -1804,7 +1858,7 @@ priv_send_turn_message (UdpTurnPriv *priv, TURNMessage *msg)
|
||
}
|
||
|
||
static gboolean
|
||
-priv_send_create_permission(UdpTurnPriv *priv, StunMessage *resp,
|
||
+priv_send_create_permission(UdpTurnPriv *priv,
|
||
const NiceAddress *peer)
|
||
{
|
||
guint msg_buf_len;
|
||
@@ -1814,17 +1868,6 @@ priv_send_create_permission(UdpTurnPriv *priv, StunMessage *resp,
|
||
struct sockaddr_storage storage;
|
||
struct sockaddr addr;
|
||
} addr;
|
||
- uint8_t *realm = NULL;
|
||
- uint16_t realm_len = 0;
|
||
- uint8_t *nonce = NULL;
|
||
- uint16_t nonce_len = 0;
|
||
-
|
||
- if (resp) {
|
||
- realm = (uint8_t *) stun_message_find (resp,
|
||
- STUN_ATTRIBUTE_REALM, &realm_len);
|
||
- nonce = (uint8_t *) stun_message_find (resp,
|
||
- STUN_ATTRIBUTE_NONCE, &nonce_len);
|
||
- }
|
||
|
||
/* register this peer as being pening a permission (if not already pending) */
|
||
if (!priv_has_sent_permission_for_peer (priv, peer)) {
|
||
@@ -1841,8 +1884,8 @@ priv_send_create_permission(UdpTurnPriv *priv, StunMessage *resp,
|
||
priv->username_len,
|
||
priv->password,
|
||
priv->password_len,
|
||
- realm, realm_len,
|
||
- nonce, nonce_len,
|
||
+ priv->cached_realm, priv->cached_realm_len,
|
||
+ priv->cached_nonce, priv->cached_nonce_len,
|
||
&addr.storage,
|
||
STUN_USAGE_TURN_COMPATIBILITY_RFC5766);
|
||
|
||
@@ -1876,8 +1919,8 @@ priv_send_create_permission(UdpTurnPriv *priv, StunMessage *resp,
|
||
}
|
||
|
||
static gboolean
|
||
-priv_send_channel_bind (UdpTurnPriv *priv, StunMessage *resp,
|
||
- uint16_t channel, const NiceAddress *peer)
|
||
+priv_send_channel_bind (UdpTurnPriv *priv, uint16_t channel,
|
||
+ const NiceAddress *peer)
|
||
{
|
||
uint32_t channel_attr = channel << 16;
|
||
size_t stun_len;
|
||
@@ -1910,37 +1953,29 @@ priv_send_channel_bind (UdpTurnPriv *priv, StunMessage *resp,
|
||
return FALSE;
|
||
}
|
||
|
||
- if (priv->username != NULL && priv->username_len > 0) {
|
||
+ if (priv->username != NULL && priv->username_len > 0 &&
|
||
+ priv->cached_realm != NULL && priv->cached_realm_len > 0 &&
|
||
+ priv->cached_nonce != NULL && priv->cached_nonce_len > 0) {
|
||
+
|
||
if (stun_message_append_bytes (&msg->message, STUN_ATTRIBUTE_USERNAME,
|
||
priv->username, priv->username_len)
|
||
!= STUN_MESSAGE_RETURN_SUCCESS) {
|
||
g_free (msg);
|
||
return FALSE;
|
||
}
|
||
- }
|
||
-
|
||
- if (resp) {
|
||
- uint8_t *realm;
|
||
- uint8_t *nonce;
|
||
- uint16_t len;
|
||
|
||
- realm = (uint8_t *) stun_message_find (resp, STUN_ATTRIBUTE_REALM, &len);
|
||
- if (realm != NULL) {
|
||
- if (stun_message_append_bytes (&msg->message, STUN_ATTRIBUTE_REALM,
|
||
- realm, len)
|
||
- != STUN_MESSAGE_RETURN_SUCCESS) {
|
||
- g_free (msg);
|
||
- return 0;
|
||
- }
|
||
+ if (stun_message_append_bytes (&msg->message, STUN_ATTRIBUTE_REALM,
|
||
+ priv->cached_realm, priv->cached_realm_len)
|
||
+ != STUN_MESSAGE_RETURN_SUCCESS) {
|
||
+ g_free (msg);
|
||
+ return 0;
|
||
}
|
||
- nonce = (uint8_t *) stun_message_find (resp, STUN_ATTRIBUTE_NONCE, &len);
|
||
- if (nonce != NULL) {
|
||
- if (stun_message_append_bytes (&msg->message, STUN_ATTRIBUTE_NONCE,
|
||
- nonce, len)
|
||
- != STUN_MESSAGE_RETURN_SUCCESS) {
|
||
- g_free (msg);
|
||
- return 0;
|
||
- }
|
||
+
|
||
+ if (stun_message_append_bytes (&msg->message, STUN_ATTRIBUTE_NONCE,
|
||
+ priv->cached_nonce, priv->cached_nonce_len)
|
||
+ != STUN_MESSAGE_RETURN_SUCCESS) {
|
||
+ g_free (msg);
|
||
+ return 0;
|
||
}
|
||
}
|
||
|
||
@@ -1988,7 +2023,7 @@ priv_add_channel_binding (UdpTurnPriv *priv, const NiceAddress *peer)
|
||
}
|
||
|
||
if (channel >= 0x4000 && channel < 0xffff) {
|
||
- gboolean ret = priv_send_channel_bind (priv, NULL, channel, peer);
|
||
+ gboolean ret = priv_send_channel_bind (priv, channel, peer);
|
||
if (ret) {
|
||
priv->current_binding = g_new0 (ChannelBinding, 1);
|
||
priv->current_binding->channel = channel;
|
||
diff --git a/socket/udp-turn.h b/socket/udp-turn.h
|
||
index ba31636..b1eeeb4 100644
|
||
--- a/socket/udp-turn.h
|
||
+++ b/socket/udp-turn.h
|
||
@@ -75,6 +75,9 @@ nice_udp_turn_socket_set_ms_realm(NiceSocket *sock, StunMessage *msg);
|
||
void
|
||
nice_udp_turn_socket_set_ms_connection_id (NiceSocket *sock, StunMessage *msg);
|
||
|
||
+void
|
||
+nice_udp_turn_socket_cache_realm_nonce (NiceSocket *sock, StunMessage *msg);
|
||
+
|
||
|
||
G_END_DECLS
|
||
|
||
diff --git a/stun/debug.c b/stun/debug.c
|
||
index 2b4ec59..8efb576 100644
|
||
--- a/stun/debug.c
|
||
+++ b/stun/debug.c
|
||
@@ -46,7 +46,7 @@
|
||
#include "debug.h"
|
||
|
||
|
||
-static int debug_enabled = 1;
|
||
+static int debug_enabled = 0;
|
||
|
||
void stun_debug_enable (void) {
|
||
debug_enabled = 1;
|
||
diff --git a/stun/stunagent.c b/stun/stunagent.c
|
||
index 2abcc29..bd243cb 100644
|
||
--- a/stun/stunagent.c
|
||
+++ b/stun/stunagent.c
|
||
@@ -513,8 +513,20 @@ size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg,
|
||
uint32_t fpr;
|
||
int saved_id_idx = 0;
|
||
uint8_t md5[16];
|
||
+ bool remember_transaction;
|
||
|
||
- if (stun_message_get_class (msg) == STUN_REQUEST) {
|
||
+ remember_transaction = (stun_message_get_class (msg) == STUN_REQUEST);
|
||
+
|
||
+ if (agent->compatibility == STUN_COMPATIBILITY_OC2007 &&
|
||
+ stun_message_get_method (msg) == STUN_SEND) {
|
||
+ /* As per [MS-TURN] Section 2.2.1, the TURN server doesn't send responses to
|
||
+ * STUN_SEND requests, so don't bother waiting for them. More details at
|
||
+ * https://msdn.microsoft.com/en-us/library/dd946797%28v=office.12%29.aspx.
|
||
+ */
|
||
+ remember_transaction = FALSE;
|
||
+ }
|
||
+
|
||
+ if (remember_transaction) {
|
||
for (saved_id_idx = 0; saved_id_idx < STUN_AGENT_MAX_SAVED_IDS; saved_id_idx++) {
|
||
if (agent->sent_ids[saved_id_idx].valid == FALSE) {
|
||
break;
|
||
@@ -620,7 +632,7 @@ size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg,
|
||
}
|
||
|
||
|
||
- if (stun_message_get_class (msg) == STUN_REQUEST) {
|
||
+ if (remember_transaction) {
|
||
stun_message_id (msg, agent->sent_ids[saved_id_idx].id);
|
||
agent->sent_ids[saved_id_idx].method = stun_message_get_method (msg);
|
||
agent->sent_ids[saved_id_idx].key = (uint8_t *) key;
|
||
diff --git a/stun/stunmessage.c b/stun/stunmessage.c
|
||
index 9faa64b..558fe5e 100644
|
||
--- a/stun/stunmessage.c
|
||
+++ b/stun/stunmessage.c
|
||
@@ -550,7 +550,6 @@ ssize_t stun_message_validate_buffer_length_fast (StunInputVector *buffers,
|
||
|
||
if (buffers[0].buffer[0] >> 6)
|
||
{
|
||
- stun_debug ("STUN error: RTP or other non-protocol packet!");
|
||
return STUN_MESSAGE_BUFFER_INVALID; // RTP or other non-STUN packet
|
||
}
|
||
|
||
diff --git a/stun/tests/test-bind.c b/stun/tests/test-bind.c
|
||
index 0c7646f..2cf4feb 100644
|
||
--- a/stun/tests/test-bind.c
|
||
+++ b/stun/tests/test-bind.c
|
||
@@ -438,7 +438,7 @@ static void keepalive (void)
|
||
|
||
static void test (void (*func) (void), const char *name)
|
||
{
|
||
- alarm (20);
|
||
+ alarm (30);
|
||
|
||
printf ("%s test... ", name);
|
||
func ();
|
||
diff --git a/stun/tests/test-conncheck.c b/stun/tests/test-conncheck.c
|
||
index 610d43a..92b947c 100644
|
||
--- a/stun/tests/test-conncheck.c
|
||
+++ b/stun/tests/test-conncheck.c
|
||
@@ -213,7 +213,7 @@ int main (void)
|
||
|
||
addr.ip4.sin_family = AF_INET;
|
||
|
||
- /* Lost role conflict */
|
||
+ /* Role conflict, controlling + ICE-CONTROLLING, switching controlled */
|
||
assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING));
|
||
val = stun_message_append64 (&req, STUN_ATTRIBUTE_ICE_CONTROLLING, tie + 1);
|
||
assert (val == STUN_MESSAGE_RETURN_SUCCESS);
|
||
@@ -223,7 +223,6 @@ int main (void)
|
||
rlen = stun_agent_finish_message (&agent, &req, pass, pass_len);
|
||
assert (rlen > 0);
|
||
|
||
-
|
||
len = sizeof (resp_buf);
|
||
control = true;
|
||
val2 = stun_usage_ice_conncheck_create_reply (&agent, &req,
|
||
@@ -236,7 +235,7 @@ int main (void)
|
||
stun_agent_default_validater, validater_data) == STUN_VALIDATION_SUCCESS);
|
||
assert (stun_message_get_class (&resp) == STUN_RESPONSE);
|
||
|
||
- /* Won role conflict */
|
||
+ /* Role conflict, controlled + ICE-CONTROLLED, switching controlling */
|
||
assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING));
|
||
val = stun_message_append64 (&req, STUN_ATTRIBUTE_ICE_CONTROLLED, tie - 1);
|
||
assert (val == STUN_MESSAGE_RETURN_SUCCESS);
|
||
@@ -251,15 +250,60 @@ int main (void)
|
||
val2 = stun_usage_ice_conncheck_create_reply (&agent, &req,
|
||
&resp, resp_buf, &len, &addr.storage,
|
||
sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245);
|
||
- assert (val2 == STUN_USAGE_ICE_RETURN_SUCCESS);
|
||
+ assert (val2 == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT);
|
||
assert (len > 0);
|
||
- assert (control == false);
|
||
+ assert (control == true);
|
||
+ assert (stun_agent_validate (&agent, &resp, resp_buf, len,
|
||
+ stun_agent_default_validater, validater_data) == STUN_VALIDATION_SUCCESS);
|
||
+ assert (stun_message_get_class (&resp) == STUN_RESPONSE);
|
||
+
|
||
+ /* Role conflict, controlling + ICE-CONTROLLING, staying controlling */
|
||
+ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING));
|
||
+ val = stun_message_append64 (&req, STUN_ATTRIBUTE_ICE_CONTROLLING, tie - 1);
|
||
+ assert (val == STUN_MESSAGE_RETURN_SUCCESS);
|
||
+ val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME,
|
||
+ (char *) ufrag);
|
||
+ assert (val == STUN_MESSAGE_RETURN_SUCCESS);
|
||
+ rlen = stun_agent_finish_message (&agent, &req, pass, pass_len);
|
||
+ assert (rlen > 0);
|
||
+
|
||
+ len = sizeof (resp_buf);
|
||
+ control = true;
|
||
+ val2 = stun_usage_ice_conncheck_create_reply (&agent, &req,
|
||
+ &resp, resp_buf, &len, &addr.storage,
|
||
+ sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245);
|
||
+ assert (val2 == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT);
|
||
+ assert (len > 0);
|
||
+ assert (control == true);
|
||
assert (stun_agent_validate (&agent, &resp, resp_buf, len,
|
||
stun_agent_default_validater, validater_data) == STUN_VALIDATION_SUCCESS);
|
||
assert (stun_message_get_class (&resp) == STUN_ERROR);
|
||
stun_message_find_error (&resp, &code);
|
||
assert (code == STUN_ERROR_ROLE_CONFLICT);
|
||
|
||
+ /* Role conflict, controlled + ICE-CONTROLLED, staying controlling */
|
||
+ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING));
|
||
+ val = stun_message_append64 (&req, STUN_ATTRIBUTE_ICE_CONTROLLED, tie + 1);
|
||
+ assert (val == STUN_MESSAGE_RETURN_SUCCESS);
|
||
+ val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME,
|
||
+ (char *) ufrag);
|
||
+ assert (val == STUN_MESSAGE_RETURN_SUCCESS);
|
||
+ rlen = stun_agent_finish_message (&agent, &req, pass, pass_len);
|
||
+ assert (rlen > 0);
|
||
+
|
||
+ len = sizeof (resp_buf);
|
||
+ control = false;
|
||
+ val2 = stun_usage_ice_conncheck_create_reply (&agent, &req,
|
||
+ &resp, resp_buf, &len, &addr.storage,
|
||
+ sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245);
|
||
+ assert (val2 == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT);
|
||
+ assert (len > 0);
|
||
+ assert (control == false);
|
||
+ assert (stun_agent_validate (&agent, &resp, resp_buf, len,
|
||
+ stun_agent_default_validater, validater_data) == STUN_VALIDATION_SUCCESS);
|
||
+ assert (stun_message_get_class (&resp) == STUN_ERROR);
|
||
+ stun_message_find_error (&resp, &code);
|
||
+ assert (code == STUN_ERROR_ROLE_CONFLICT);
|
||
|
||
return 0;
|
||
}
|
||
diff --git a/stun/usages/ice.c b/stun/usages/ice.c
|
||
index a628791..a7d0d19 100644
|
||
--- a/stun/usages/ice.c
|
||
+++ b/stun/usages/ice.c
|
||
@@ -265,9 +265,17 @@ stun_usage_ice_conncheck_create_reply (StunAgent *agent, StunMessage *req,
|
||
if (stun_message_find64 (req, *control ? STUN_ATTRIBUTE_ICE_CONTROLLING
|
||
: STUN_ATTRIBUTE_ICE_CONTROLLED, &q) == STUN_MESSAGE_RETURN_SUCCESS)
|
||
{
|
||
+ /* we have the ice-controlling/controlled attribute,
|
||
+ * and there's a role conflict
|
||
+ */
|
||
stun_debug ("STUN Role Conflict detected:");
|
||
|
||
- if (tie < q)
|
||
+ /* According to ICE RFC 5245, section 7.2.1.1, we consider the four
|
||
+ * possible cases when a role conflict is detected: two cases are
|
||
+ * resolved by switching role locally, and the two other cases are
|
||
+ * handled by responding with a STUN error.
|
||
+ */
|
||
+ if ((tie < q && *control) || (tie >= q && !*control))
|
||
{
|
||
stun_debug (" switching role from \"controll%s\" to \"controll%s\"",
|
||
*control ? "ing" : "ed", *control ? "ed" : "ing");
|
||
@@ -279,10 +287,21 @@ stun_usage_ice_conncheck_create_reply (StunAgent *agent, StunMessage *req,
|
||
stun_debug (" staying \"controll%s\" (sending error)",
|
||
*control ? "ing" : "ed");
|
||
err (STUN_ERROR_ROLE_CONFLICT);
|
||
- return STUN_USAGE_ICE_RETURN_SUCCESS;
|
||
+ return STUN_USAGE_ICE_RETURN_ROLE_CONFLICT;
|
||
}
|
||
} else {
|
||
- stun_debug ("STUN Role not specified by peer!");
|
||
+ if (stun_message_find64 (req, *control ? STUN_ATTRIBUTE_ICE_CONTROLLED
|
||
+ : STUN_ATTRIBUTE_ICE_CONTROLLING, &q) != STUN_MESSAGE_RETURN_SUCCESS)
|
||
+ {
|
||
+ /* we don't have the expected ice-controlling/controlled
|
||
+ * attribute
|
||
+ */
|
||
+ if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_RFC5245 ||
|
||
+ compatibility == STUN_USAGE_ICE_COMPATIBILITY_WLM2009)
|
||
+ {
|
||
+ stun_debug ("STUN Role not specified by peer!");
|
||
+ }
|
||
+ }
|
||
}
|
||
|
||
if (stun_agent_init_response (agent, msg, buf, len, req) == FALSE) {
|
||
diff --git a/stun/usages/timer.c b/stun/usages/timer.c
|
||
index 82f3ea2..2862ab8 100644
|
||
--- a/stun/usages/timer.c
|
||
+++ b/stun/usages/timer.c
|
||
@@ -104,7 +104,7 @@ void stun_timer_start (StunTimer *timer, unsigned int initial_timeout,
|
||
unsigned int max_retransmissions)
|
||
{
|
||
stun_gettime (&timer->deadline);
|
||
- timer->retransmissions = 0;
|
||
+ timer->retransmissions = 1;
|
||
timer->delay = initial_timeout;
|
||
timer->max_retransmissions = max_retransmissions;
|
||
add_delay (&timer->deadline, timer->delay);
|
||
diff --git a/stun/usages/timer.h b/stun/usages/timer.h
|
||
index e6501cb..e74353b 100644
|
||
--- a/stun/usages/timer.h
|
||
+++ b/stun/usages/timer.h
|
||
@@ -130,15 +130,18 @@ struct stun_timer_s {
|
||
* STUN_TIMER_DEFAULT_TIMEOUT:
|
||
*
|
||
* The default intial timeout to use for the timer
|
||
+ * RFC recommendds 500, but it's ridiculous, 50ms is known to work in most
|
||
+ * cases as it is also what is used by SIP style VoIP when sending A-Law and
|
||
+ * mu-Law audio, so 200ms should be hyper safe.
|
||
*/
|
||
-#define STUN_TIMER_DEFAULT_TIMEOUT 600
|
||
+#define STUN_TIMER_DEFAULT_TIMEOUT 200
|
||
|
||
/**
|
||
* STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS:
|
||
*
|
||
* The default maximum retransmissions allowed before a timer decides to timeout
|
||
*/
|
||
-#define STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS 3
|
||
+#define STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS 7
|
||
|
||
/**
|
||
* STUN_TIMER_DEFAULT_RELIABLE_TIMEOUT:
|
||
diff --git a/stun/usages/turn.c b/stun/usages/turn.c
|
||
index f242650..3b94959 100644
|
||
--- a/stun/usages/turn.c
|
||
+++ b/stun/usages/turn.c
|
||
@@ -152,7 +152,9 @@ size_t stun_usage_turn_create (StunAgent *agent, StunMessage *msg,
|
||
}
|
||
}
|
||
|
||
- if (username != NULL && username_len > 0) {
|
||
+ if (username != NULL && username_len > 0 &&
|
||
+ (agent->usage_flags & STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS ||
|
||
+ previous_response)) {
|
||
if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME,
|
||
username, username_len) != STUN_MESSAGE_RETURN_SUCCESS)
|
||
return 0;
|
||
@@ -205,7 +207,9 @@ size_t stun_usage_turn_create_refresh (StunAgent *agent, StunMessage *msg,
|
||
}
|
||
|
||
|
||
- if (username != NULL && username_len > 0) {
|
||
+ if (username != NULL && username_len > 0 &&
|
||
+ (agent->usage_flags & STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS ||
|
||
+ previous_response)) {
|
||
if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME,
|
||
username, username_len) != STUN_MESSAGE_RETURN_SUCCESS)
|
||
return 0;
|
||
@@ -251,7 +255,9 @@ size_t stun_usage_turn_create_permission (StunAgent *agent, StunMessage *msg,
|
||
}
|
||
|
||
/* username */
|
||
- if (username != NULL) {
|
||
+ if (username != NULL &&
|
||
+ (agent->usage_flags & STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS ||
|
||
+ (nonce != NULL && realm != NULL))) {
|
||
if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME,
|
||
username, username_len) != STUN_MESSAGE_RETURN_SUCCESS)
|
||
return 0;
|
||
diff --git a/tests/Makefile.am b/tests/Makefile.am
|
||
index 3644091..7bfe075 100644
|
||
--- a/tests/Makefile.am
|
||
+++ b/tests/Makefile.am
|
||
@@ -22,6 +22,10 @@ AM_CFLAGS = \
|
||
-I $(top_srcdir)/stun
|
||
AM_CPPFLAGS = -DG_LOG_DOMAIN=\"libnice-tests\"
|
||
|
||
+AM_TESTS_ENVIRONMENT = \
|
||
+ G_MESSAGES_DEBUG=all \
|
||
+ NICE_DEBUG=all;
|
||
+
|
||
COMMON_LDADD = $(top_builddir)/agent/libagent.la $(top_builddir)/socket/libsocket.la $(GLIB_LIBS) $(GUPNP_LIBS)
|
||
|
||
check_PROGRAMS = \
|
||
@@ -39,6 +43,7 @@ check_PROGRAMS = \
|
||
test-io-stream-cancelling \
|
||
test-io-stream-pollable \
|
||
test-send-recv \
|
||
+ test-socket-is-based-on \
|
||
test-priority \
|
||
test-mainloop \
|
||
test-fullmode \
|
||
@@ -49,7 +54,8 @@ check_PROGRAMS = \
|
||
test-new-dribble \
|
||
test-tcp \
|
||
test-icetcp \
|
||
- test-credentials
|
||
+ test-credentials \
|
||
+ test-turn
|
||
|
||
dist_check_SCRIPTS = \
|
||
check-test-fullmode-with-stun.sh \
|
||
@@ -99,6 +105,8 @@ test_io_stream_pollable_LDADD = $(COMMON_LDADD)
|
||
test_send_recv_SOURCES = test-send-recv.c test-io-stream-common.c
|
||
test_send_recv_LDADD = $(COMMON_LDADD)
|
||
|
||
+test_socket_is_based_on_LDADD = $(COMMON_LDADD)
|
||
+
|
||
test_priority_LDADD = $(COMMON_LDADD)
|
||
|
||
test_mainloop_LDADD = $(COMMON_LDADD)
|
||
@@ -119,6 +127,8 @@ test_icetcp_LDADD = $(COMMON_LDADD)
|
||
|
||
test_credentials_LDADD = $(COMMON_LDADD)
|
||
|
||
+test_turn_LDADD = $(COMMON_LDADD)
|
||
+
|
||
test_gstreamer_CFLAGS = $(AM_CFLAGS) $(GST_CHECK_CFLAGS)
|
||
test_gstreamer_LDADD = -lnice -L$(top_builddir)/nice/.libs $(GLIB_LIBS) $(GUPNP_LIBS) $(GST_CHECK_LIBS) $(GST_LIBS)
|
||
|
||
diff --git a/tests/test-add-remove-stream.c b/tests/test-add-remove-stream.c
|
||
index 5ed3463..c97bc7b 100644
|
||
--- a/tests/test-add-remove-stream.c
|
||
+++ b/tests/test-add-remove-stream.c
|
||
@@ -54,8 +54,6 @@ main (void)
|
||
WSAStartup(0x0202, &w);
|
||
#endif
|
||
nice_address_init (&addr);
|
||
- g_type_init ();
|
||
- g_thread_init (NULL);
|
||
|
||
if (!nice_address_set_from_string (&addr, "127.0.0.1"))
|
||
g_assert_not_reached ();
|
||
diff --git a/tests/test-bsd.c b/tests/test-bsd.c
|
||
index 6b747d0..c1ddf53 100644
|
||
--- a/tests/test-bsd.c
|
||
+++ b/tests/test-bsd.c
|
||
@@ -368,8 +368,6 @@ test_multi_message_recv (guint n_sends, guint n_receives,
|
||
int
|
||
main (void)
|
||
{
|
||
- g_type_init ();
|
||
-
|
||
test_socket_initial_properties ();
|
||
test_socket_address_properties ();
|
||
test_simple_send_recv ();
|
||
diff --git a/tests/test-build-io-stream.c b/tests/test-build-io-stream.c
|
||
index 0c9c593..a3478ed 100644
|
||
--- a/tests/test-build-io-stream.c
|
||
+++ b/tests/test-build-io-stream.c
|
||
@@ -440,8 +440,6 @@ main (void)
|
||
WSAStartup (0x0202, &w);
|
||
#endif
|
||
nice_address_init (&addr);
|
||
- g_type_init ();
|
||
- g_thread_init (NULL);
|
||
|
||
g_assert (nice_address_set_from_string (&addr, "127.0.0.1"));
|
||
|
||
diff --git a/tests/test-credentials.c b/tests/test-credentials.c
|
||
index f678afa..1de4e49 100644
|
||
--- a/tests/test-credentials.c
|
||
+++ b/tests/test-credentials.c
|
||
@@ -172,8 +172,6 @@ int main (void)
|
||
WSADATA w;
|
||
WSAStartup(0x0202, &w);
|
||
#endif
|
||
- g_type_init ();
|
||
- g_thread_init (NULL);
|
||
|
||
loop = g_main_loop_new (NULL, FALSE);
|
||
|
||
diff --git a/tests/test-dribble.c b/tests/test-dribble.c
|
||
index 6603129..d9de07b 100644
|
||
--- a/tests/test-dribble.c
|
||
+++ b/tests/test-dribble.c
|
||
@@ -215,9 +215,6 @@ int main (void)
|
||
WSAStartup(0x0202, &w);
|
||
#endif
|
||
|
||
- g_type_init ();
|
||
- g_thread_init (NULL);
|
||
-
|
||
global_mainloop = g_main_loop_new (NULL, FALSE);
|
||
|
||
/* step: create the agents L and R */
|
||
diff --git a/tests/test-fallback.c b/tests/test-fallback.c
|
||
index f97cb0d..34fd1d1 100644
|
||
--- a/tests/test-fallback.c
|
||
+++ b/tests/test-fallback.c
|
||
@@ -491,8 +491,6 @@ int main (void)
|
||
|
||
WSAStartup(0x0202, &w);
|
||
#endif
|
||
- g_type_init ();
|
||
- g_thread_init (NULL);
|
||
|
||
global_mainloop = g_main_loop_new (NULL, FALSE);
|
||
|
||
diff --git a/tests/test-fullmode.c b/tests/test-fullmode.c
|
||
index 03778f7..b599a24 100644
|
||
--- a/tests/test-fullmode.c
|
||
+++ b/tests/test-fullmode.c
|
||
@@ -834,8 +834,6 @@ int main (void)
|
||
|
||
WSAStartup(0x0202, &w);
|
||
#endif
|
||
- g_type_init ();
|
||
- g_thread_init(NULL);
|
||
|
||
global_mainloop = g_main_loop_new (NULL, FALSE);
|
||
|
||
diff --git a/tests/test-icetcp.c b/tests/test-icetcp.c
|
||
index 7ab3563..5b2b4b2 100644
|
||
--- a/tests/test-icetcp.c
|
||
+++ b/tests/test-icetcp.c
|
||
@@ -125,6 +125,14 @@ static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpoin
|
||
(void)agent;
|
||
}
|
||
|
||
+static void check_loop_quit_condition (void)
|
||
+{
|
||
+ if (global_ready_reached &&
|
||
+ global_lagent_cands >= 2 && global_ragent_cands >= 2) {
|
||
+ g_main_loop_quit (global_mainloop);
|
||
+ }
|
||
+}
|
||
+
|
||
static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data)
|
||
{
|
||
gboolean ready_to_connected = FALSE;
|
||
@@ -158,10 +166,10 @@ static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint
|
||
global_ready_reached == FALSE) {
|
||
g_debug ("Components ready/failed achieved. Stopping mailoop");
|
||
global_ready_reached = TRUE;
|
||
- g_main_loop_quit (global_mainloop);
|
||
- return;
|
||
}
|
||
|
||
+ check_loop_quit_condition ();
|
||
+
|
||
#if 0
|
||
/* signal status via a global variable */
|
||
if (global_components_failed == global_components_failed_exit) {
|
||
@@ -184,6 +192,8 @@ static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, guint compon
|
||
else if (GPOINTER_TO_UINT (data) == 2)
|
||
++global_ragent_cands;
|
||
|
||
+ check_loop_quit_condition ();
|
||
+
|
||
/* XXX: dear compiler, these are for you: */
|
||
(void)agent; (void)stream_id; (void)component_id; (void)lfoundation; (void)rfoundation;
|
||
}
|
||
@@ -397,10 +407,6 @@ int main (void)
|
||
|
||
WSAStartup(0x0202, &w);
|
||
#endif
|
||
- g_type_init ();
|
||
-#if !GLIB_CHECK_VERSION(2,31,8)
|
||
- g_thread_init(NULL);
|
||
-#endif
|
||
|
||
global_mainloop = g_main_loop_new (NULL, FALSE);
|
||
|
||
diff --git a/tests/test-io-stream-cancelling.c b/tests/test-io-stream-cancelling.c
|
||
index 55fc1f3..d1b9a89 100644
|
||
--- a/tests/test-io-stream-cancelling.c
|
||
+++ b/tests/test-io-stream-cancelling.c
|
||
@@ -112,8 +112,6 @@ int main (void)
|
||
WSADATA w;
|
||
WSAStartup (0x0202, &w);
|
||
#endif
|
||
- g_type_init ();
|
||
- g_thread_init (NULL);
|
||
|
||
l_data.cancellable = g_cancellable_new ();
|
||
l_data.blocking = FALSE;
|
||
diff --git a/tests/test-io-stream-closing-read.c b/tests/test-io-stream-closing-read.c
|
||
index ec434dd..5acddec 100644
|
||
--- a/tests/test-io-stream-closing-read.c
|
||
+++ b/tests/test-io-stream-closing-read.c
|
||
@@ -127,8 +127,6 @@ int main (void)
|
||
WSADATA w;
|
||
WSAStartup (0x0202, &w);
|
||
#endif
|
||
- g_type_init ();
|
||
- g_thread_init (NULL);
|
||
|
||
run_io_stream_test (30, TRUE, &callbacks, (gpointer) TRUE, NULL, NULL, NULL);
|
||
|
||
diff --git a/tests/test-io-stream-closing-write.c b/tests/test-io-stream-closing-write.c
|
||
index 97e8347..6f92f28 100644
|
||
--- a/tests/test-io-stream-closing-write.c
|
||
+++ b/tests/test-io-stream-closing-write.c
|
||
@@ -127,8 +127,6 @@ int main (void)
|
||
WSADATA w;
|
||
WSAStartup (0x0202, &w);
|
||
#endif
|
||
- g_type_init ();
|
||
- g_thread_init (NULL);
|
||
|
||
run_io_stream_test (30, TRUE, &callbacks, (gpointer) TRUE, NULL, NULL, NULL);
|
||
|
||
diff --git a/tests/test-io-stream-common.c b/tests/test-io-stream-common.c
|
||
index bd0f3b5..efa6160 100644
|
||
--- a/tests/test-io-stream-common.c
|
||
+++ b/tests/test-io-stream-common.c
|
||
@@ -335,12 +335,7 @@ spawn_thread (const gchar *thread_name, GThreadFunc thread_func,
|
||
{
|
||
GThread *thread;
|
||
|
||
-#if !GLIB_CHECK_VERSION(2, 31, 8)
|
||
- thread = g_thread_create (thread_func, user_data, TRUE, NULL);
|
||
-#else
|
||
thread = g_thread_new (thread_name, thread_func, user_data);
|
||
-#endif
|
||
-
|
||
g_assert (thread);
|
||
|
||
return thread;
|
||
diff --git a/tests/test-io-stream-pollable.c b/tests/test-io-stream-pollable.c
|
||
index 614a546..a543f88 100644
|
||
--- a/tests/test-io-stream-pollable.c
|
||
+++ b/tests/test-io-stream-pollable.c
|
||
@@ -159,8 +159,6 @@ int main (void)
|
||
WSADATA w;
|
||
WSAStartup (0x0202, &w);
|
||
#endif
|
||
- g_type_init ();
|
||
- g_thread_init (NULL);
|
||
|
||
l_data = g_malloc0 (sizeof (ThreadData));
|
||
r_data = g_malloc0 (sizeof (ThreadData));
|
||
diff --git a/tests/test-io-stream-thread.c b/tests/test-io-stream-thread.c
|
||
index db14fe4..73ecd76 100644
|
||
--- a/tests/test-io-stream-thread.c
|
||
+++ b/tests/test-io-stream-thread.c
|
||
@@ -124,8 +124,6 @@ int main (void)
|
||
WSADATA w;
|
||
WSAStartup (0x0202, &w);
|
||
#endif
|
||
- g_type_init ();
|
||
- g_thread_init (NULL);
|
||
|
||
l_data = g_malloc0 (sizeof (ThreadData));
|
||
r_data = g_malloc0 (sizeof (ThreadData));
|
||
diff --git a/tests/test-mainloop.c b/tests/test-mainloop.c
|
||
index b4e4d05..7c52daa 100644
|
||
--- a/tests/test-mainloop.c
|
||
+++ b/tests/test-mainloop.c
|
||
@@ -72,8 +72,6 @@ main (void)
|
||
guint stream;
|
||
|
||
nice_address_init (&addr);
|
||
- g_type_init ();
|
||
- g_thread_init(NULL);
|
||
|
||
loop = g_main_loop_new (NULL, FALSE);
|
||
|
||
diff --git a/tests/test-new-dribble.c b/tests/test-new-dribble.c
|
||
index 395e275..3e60ae3 100644
|
||
--- a/tests/test-new-dribble.c
|
||
+++ b/tests/test-new-dribble.c
|
||
@@ -56,21 +56,14 @@
|
||
#define LEFT_AGENT GINT_TO_POINTER(1)
|
||
#define RIGHT_AGENT GINT_TO_POINTER(2)
|
||
|
||
-#if !GLIB_CHECK_VERSION(2,31,8)
|
||
- static GMutex *stun_mutex_ptr = NULL;
|
||
- static GCond *stun_signal_ptr = NULL;
|
||
- static GMutex *stun_thread_mutex_ptr = NULL;
|
||
- static GCond *stun_thread_signal_ptr = NULL
|
||
-#else
|
||
- static GMutex stun_mutex;
|
||
- static GMutex *stun_mutex_ptr = &stun_mutex;
|
||
- static GCond stun_signal;
|
||
- static GCond *stun_signal_ptr = &stun_signal;
|
||
- static GMutex stun_thread_mutex;
|
||
- static GMutex *stun_thread_mutex_ptr = &stun_thread_mutex;
|
||
- static GCond stun_thread_signal;
|
||
- static GCond *stun_thread_signal_ptr = &stun_thread_signal;
|
||
-#endif
|
||
+static GMutex stun_mutex;
|
||
+static GMutex *stun_mutex_ptr = &stun_mutex;
|
||
+static GCond stun_signal;
|
||
+static GCond *stun_signal_ptr = &stun_signal;
|
||
+static GMutex stun_thread_mutex;
|
||
+static GMutex *stun_thread_mutex_ptr = &stun_thread_mutex;
|
||
+static GCond stun_thread_signal;
|
||
+static GCond *stun_thread_signal_ptr = &stun_thread_signal;
|
||
|
||
static NiceComponentState global_lagent_state = NICE_COMPONENT_STATE_LAST;
|
||
static NiceComponentState global_ragent_state = NICE_COMPONENT_STATE_LAST;
|
||
@@ -530,6 +523,10 @@ static void standard_test(NiceAgent *lagent, NiceAgent *ragent)
|
||
|
||
g_assert (lagent_candidate_gathering_done);
|
||
|
||
+ while (global_ragent_state < NICE_COMPONENT_STATE_CONNECTED)
|
||
+ g_main_context_iteration (NULL, TRUE);
|
||
+ g_cancellable_reset (global_cancellable);
|
||
+
|
||
g_assert (global_lagent_state == NICE_COMPONENT_STATE_READY);
|
||
g_assert (global_ragent_state >= NICE_COMPONENT_STATE_CONNECTED);
|
||
|
||
@@ -725,8 +722,6 @@ int main(void)
|
||
GSource *src;
|
||
int sock;
|
||
|
||
- g_type_init();
|
||
-
|
||
global_cancellable = g_cancellable_new ();
|
||
src = g_cancellable_source_new (global_cancellable);
|
||
g_source_set_dummy_callback (src);
|
||
@@ -739,16 +734,8 @@ int main(void)
|
||
}
|
||
|
||
|
||
-#if !GLIB_CHECK_VERSION(2,31,8)
|
||
- g_thread_init (NULL);
|
||
- stun_thread = g_thread_create (stun_thread_func, GINT_TO_POINTER (sock),
|
||
- TRUE, NULL);
|
||
- stun_mutex_ptr = g_mutex_new ();
|
||
- stun_signal_ptr = g_cond_new ();
|
||
-#else
|
||
stun_thread = g_thread_new ("listen for STUN requests",
|
||
stun_thread_func, GINT_TO_POINTER (sock));
|
||
-#endif
|
||
|
||
// Once the the thread is forked, we want to listen for a signal
|
||
// that the socket was opened successfully
|
||
@@ -803,10 +790,6 @@ int main(void)
|
||
g_object_unref (ragent);
|
||
|
||
g_thread_join (stun_thread);
|
||
-#if !GLIB_CHECK_VERSION(2,31,8)
|
||
- g_mutex_free (stun_mutex_ptr);
|
||
- g_cond_free (stun_signal_ptr);
|
||
-#endif
|
||
g_object_unref (global_cancellable);
|
||
|
||
g_source_destroy (src);
|
||
diff --git a/tests/test-priority.c b/tests/test-priority.c
|
||
index f7d3273..1700dd0 100644
|
||
--- a/tests/test-priority.c
|
||
+++ b/tests/test-priority.c
|
||
@@ -47,38 +47,41 @@ main (void)
|
||
{
|
||
NiceCandidate *candidate;
|
||
|
||
- /* test 1 */
|
||
candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_HOST);
|
||
- g_assert (nice_candidate_jingle_priority (candidate) == 1000);
|
||
+ nice_address_set_from_string (&candidate->addr, "127.0.0.1");
|
||
+ nice_address_set_from_string (&candidate->base_addr, "127.0.0.1");
|
||
+
|
||
+ /* test 1 */
|
||
+ g_assert_cmpuint (nice_candidate_jingle_priority (candidate), ==, 1000);
|
||
/* Host UDP */
|
||
candidate->transport = NICE_CANDIDATE_TRANSPORT_UDP;
|
||
candidate->component_id = 1;
|
||
- g_assert (nice_candidate_ice_priority (candidate, FALSE, FALSE) == 0x780001FF);
|
||
+ g_assert_cmpuint (nice_candidate_ice_priority (candidate, FALSE, FALSE), ==, 0x780001FF);
|
||
/* Host UDP reliable */
|
||
- g_assert (nice_candidate_ice_priority (candidate, TRUE, FALSE) == 0x3C0001FF);
|
||
+ g_assert_cmpuint (nice_candidate_ice_priority (candidate, TRUE, FALSE), ==, 0x3C0001FF);
|
||
/* Host tcp-active unreliable */
|
||
candidate->transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE;
|
||
- g_assert (nice_candidate_ice_priority (candidate, FALSE, FALSE) == 0x3CC001FF);
|
||
+ g_assert_cmpuint (nice_candidate_ice_priority (candidate, FALSE, FALSE) & 0xFFE000FF, ==, 0x3CC000FF);
|
||
/* Host tcp-active reliable */
|
||
candidate->transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE;
|
||
/* Host tcp-active reliable */
|
||
- g_assert (nice_candidate_ice_priority (candidate, TRUE, FALSE) == 0x78C001FF);
|
||
+ g_assert_cmpuint (nice_candidate_ice_priority (candidate, TRUE, FALSE) & 0xFFE000FF, ==, 0x78C000FF);
|
||
/* srv-reflexive tcp-active reliable */
|
||
candidate->type = NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE;
|
||
candidate->transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE;
|
||
- g_assert (nice_candidate_ice_priority (candidate, TRUE, FALSE) == 0x648001FF);
|
||
+ g_assert_cmpuint (nice_candidate_ice_priority (candidate, TRUE, FALSE) & 0xFFE000FF, ==, 0x648000FF);
|
||
/* nat-assisted srv-reflexive tcp-active reliable */
|
||
- g_assert (nice_candidate_ice_priority (candidate, TRUE, TRUE) == 0x698001FF);
|
||
+ g_assert_cmpuint (nice_candidate_ice_priority (candidate, TRUE, TRUE) & 0xFFE000FF, ==, 0x698000FF);
|
||
nice_candidate_free (candidate);
|
||
|
||
/* test 2 */
|
||
/* 2^32*MIN(O,A) + 2*MAX(O,A) + (O>A?1:0)
|
||
= 2^32*1 + 2*5000 + 0
|
||
= 4294977296 */
|
||
- g_assert (nice_candidate_pair_priority (1,5000) == 4294977296LL);
|
||
+ g_assert_cmpuint (nice_candidate_pair_priority (1,5000), ==, 4294977296LL);
|
||
|
||
/* 2^32*1 + 2*5000 + 1 = 4294977297 */
|
||
- g_assert (nice_candidate_pair_priority (5000, 1) == 4294977297LL);
|
||
+ g_assert_cmpuint (nice_candidate_pair_priority (5000, 1), ==, 4294977297LL);
|
||
|
||
return 0;
|
||
}
|
||
diff --git a/tests/test-pseudotcp-fin.c b/tests/test-pseudotcp-fin.c
|
||
index b769161..d240c96 100644
|
||
--- a/tests/test-pseudotcp-fin.c
|
||
+++ b/tests/test-pseudotcp-fin.c
|
||
@@ -1,7 +1,7 @@
|
||
/*
|
||
* This file is part of the Nice GLib ICE library.
|
||
*
|
||
- * (C) 2014 Collabora Ltd.
|
||
+ * © 2014, 2015 Collabora Ltd.
|
||
* Contact: Philip Withnall
|
||
*
|
||
* The contents of this file are subject to the Mozilla Public License Version
|
||
@@ -269,6 +269,13 @@ expect_syn_received (Data *data)
|
||
expect_segment (data->right, data->right_sent, 0, 7, 7, FLAG_SYN);
|
||
}
|
||
|
||
+static void
|
||
+assert_empty_queues (Data *data)
|
||
+{
|
||
+ g_assert_cmpuint (g_queue_get_length (data->left_sent), ==, 0);
|
||
+ g_assert_cmpuint (g_queue_get_length (data->right_sent), ==, 0);
|
||
+}
|
||
+
|
||
/* Return whether the socket accepted the packet. */
|
||
static gboolean
|
||
forward_segment (GQueue/*<owned GBytes>*/ *from, PseudoTcpSocket *to)
|
||
@@ -453,6 +460,8 @@ establish_connection (Data *data)
|
||
expect_ack (data->left, data->left_sent, 7, 7);
|
||
forward_segment_ltr (data);
|
||
expect_sockets_connected (data);
|
||
+
|
||
+ assert_empty_queues (data);
|
||
}
|
||
|
||
/* Helper to close the LHS of a socket pair which has not transmitted any
|
||
@@ -638,7 +647,7 @@ pseudotcp_close_normal_recovery1 (void)
|
||
expect_fin (data.left, data.left_sent, 7, 7);
|
||
drop_segment (data.left, data.left_sent);
|
||
|
||
- increment_time_both (&data, 300); /* retransmit timeout */
|
||
+ increment_time_both (&data, 1100); /* retransmit timeout */
|
||
|
||
expect_fin (data.left, data.left_sent, 7, 7);
|
||
forward_segment_ltr (&data);
|
||
@@ -673,7 +682,7 @@ pseudotcp_close_normal_recovery2 (void)
|
||
|
||
expect_ack (data.right, data.right_sent, 7, 8);
|
||
drop_segment (data.right, data.right_sent);
|
||
- increment_time_both (&data, 300); /* retransmit timeout */
|
||
+ increment_time_both (&data, 1100); /* retransmit timeout */
|
||
expect_fin (data.left, data.left_sent, 7, 7);
|
||
forward_segment_ltr (&data);
|
||
expect_ack (data.right, data.right_sent, 7, 8);
|
||
@@ -753,6 +762,76 @@ pseudotcp_close_normal_recovery4 (void)
|
||
data_clear (&data);
|
||
}
|
||
|
||
+/* Check that closing a connection recovers from a data segment being dropped
|
||
+ * immediately before the first FIN is sent. Based on: RFC 793, Figure 13. */
|
||
+static void
|
||
+pseudotcp_close_normal_recovery_data (void)
|
||
+{
|
||
+ Data data = { 0, };
|
||
+
|
||
+ /* Establish a connection. */
|
||
+ establish_connection (&data);
|
||
+
|
||
+ /* Send some data from LHS to RHS, but drop the segment. */
|
||
+ g_assert_cmpint (pseudo_tcp_socket_send (data.left, "foo", 3), ==, 3);
|
||
+ expect_data (data.left, data.left_sent, 7, 7, 3);
|
||
+ drop_segment (data.left, data.left_sent);
|
||
+
|
||
+ assert_empty_queues(&data);
|
||
+
|
||
+ /* Close the LHS. */
|
||
+ g_assert_cmpint (pseudo_tcp_socket_get_available_bytes (data.left), ==, 0);
|
||
+ g_assert_cmpint (pseudo_tcp_socket_get_available_bytes (data.right), ==, 0);
|
||
+ close_socket (data.left);
|
||
+
|
||
+ expect_socket_state (data.left, TCP_FIN_WAIT_1);
|
||
+ expect_fin (data.left, data.left_sent, 10, 7);
|
||
+ forward_segment_ltr (&data);
|
||
+
|
||
+ expect_socket_state (data.right, TCP_ESTABLISHED);
|
||
+ expect_ack (data.right, data.right_sent, 7, 7);
|
||
+ forward_segment_rtl (&data);
|
||
+
|
||
+ expect_socket_state (data.left, TCP_FIN_WAIT_1);
|
||
+
|
||
+ assert_empty_queues(&data);
|
||
+
|
||
+ /* Close the RHS. */
|
||
+ close_socket (data.right);
|
||
+
|
||
+ expect_socket_state (data.right, TCP_FIN_WAIT_1);
|
||
+
|
||
+ expect_fin (data.right, data.right_sent, 7, 7);
|
||
+ forward_segment_rtl (&data);
|
||
+
|
||
+ expect_socket_state (data.left, TCP_CLOSING);
|
||
+
|
||
+ expect_ack (data.left, data.left_sent, 11, 8);
|
||
+ forward_segment_ltr (&data);
|
||
+
|
||
+ expect_socket_state (data.right, TCP_FIN_WAIT_2);
|
||
+
|
||
+ expect_data (data.right, data.right_sent, 8, 7, 0);
|
||
+ forward_segment_rtl (&data);
|
||
+ expect_socket_state (data.left, TCP_CLOSING);
|
||
+
|
||
+ expect_data (data.left, data.left_sent, 7, 8, 3);
|
||
+ forward_segment_ltr (&data);
|
||
+ expect_socket_state (data.right, TCP_TIME_WAIT);
|
||
+
|
||
+ increment_time_both (&data, 100); /* Delayed ACK */
|
||
+
|
||
+ expect_ack (data.right, data.right_sent, 8, 11);
|
||
+ forward_segment_rtl (&data);
|
||
+ expect_socket_state (data.left, TCP_TIME_WAIT);
|
||
+
|
||
+ increment_time_both (&data, 10); /* TIME-WAIT */
|
||
+
|
||
+ expect_sockets_closed (&data);
|
||
+
|
||
+ data_clear (&data);
|
||
+}
|
||
+
|
||
/* Check that if both FIN segments from a simultaneous FIN handshake are
|
||
* dropped, the handshake recovers and completes successfully.
|
||
* See: RFC 793, Figure 14. */
|
||
@@ -773,7 +852,7 @@ pseudotcp_close_simultaneous_recovery1 (void)
|
||
drop_segment (data.left, data.left_sent);
|
||
drop_segment (data.right, data.right_sent);
|
||
|
||
- increment_time_both (&data, 400); /* retransmit timeout */
|
||
+ increment_time_both (&data, 1200); /* retransmit timeout */
|
||
|
||
expect_fin (data.left, data.left_sent, 7, 7);
|
||
expect_fin (data.right, data.right_sent, 7, 7);
|
||
@@ -817,7 +896,7 @@ pseudotcp_close_simultaneous_recovery2 (void)
|
||
drop_segment (data.left, data.left_sent);
|
||
drop_segment (data.right, data.right_sent);
|
||
|
||
- increment_time_both (&data, 400); /* retransmit timeout */
|
||
+ increment_time_both (&data, 1200); /* retransmit timeout */
|
||
|
||
expect_fin (data.left, data.left_sent, 7, 8);
|
||
expect_fin (data.right, data.right_sent, 7, 8);
|
||
@@ -977,11 +1056,14 @@ pseudotcp_close_rst_afterwards (void)
|
||
|
||
/* Close the LHS. */
|
||
g_assert_cmpint (pseudo_tcp_socket_get_available_bytes (data.left), ==, 0);
|
||
+ pseudo_tcp_socket_close (data.left, TRUE);
|
||
close_socket (data.left);
|
||
|
||
- expect_fin (data.left, data.left_sent, 7, 7);
|
||
+ expect_rst (data.left, data.left_sent, 7, 7);
|
||
drop_segment (data.left, data.left_sent); /* just to get it out of the way */
|
||
|
||
+ assert_empty_queues(&data);
|
||
+
|
||
/* Send some data from RHS to LHS, which should result in an RST. */
|
||
g_assert_cmpint (pseudo_tcp_socket_send (data.right, "foo", 3), ==, 3);
|
||
expect_data (data.right, data.right_sent, 7, 7, 3);
|
||
@@ -1059,6 +1141,63 @@ pseudotcp_compatibility (void)
|
||
data_clear (&data);
|
||
}
|
||
|
||
+
|
||
+/* Check that after receiving a FIN, queued data can still be read */
|
||
+static void
|
||
+pseudotcp_close_recv_queued (void)
|
||
+{
|
||
+ Data data = { 0, };
|
||
+ guint8 buf[100];
|
||
+
|
||
+ /* Establish a connection. */
|
||
+ establish_connection (&data);
|
||
+
|
||
+ g_assert_cmpint (pseudo_tcp_socket_get_available_bytes (data.left), ==, 0);
|
||
+ g_assert_cmpint (pseudo_tcp_socket_get_available_bytes (data.right), ==, 0);
|
||
+ g_assert_cmpint (pseudo_tcp_socket_get_available_send_space (data.right), >,
|
||
+ 0);
|
||
+ g_assert_cmpint (pseudo_tcp_socket_get_available_send_space (data.left), >,
|
||
+ 0);
|
||
+
|
||
+ g_assert_cmpint (pseudo_tcp_socket_send (data.left, "foo", 3), ==, 3);
|
||
+ expect_data (data.left, data.left_sent, 7, 7, 3);
|
||
+ forward_segment_ltr (&data);
|
||
+
|
||
+ increment_time_both (&data, 100); /* Delayed ACK */
|
||
+ expect_ack (data.right, data.right_sent, 7, 10);
|
||
+ forward_segment_rtl (&data);
|
||
+
|
||
+ close_socket (data.left);
|
||
+ expect_fin (data.left, data.left_sent, 10, 7);
|
||
+ forward_segment_ltr (&data);
|
||
+
|
||
+ expect_socket_state (data.left, TCP_FIN_WAIT_1);
|
||
+ expect_socket_state (data.right, TCP_CLOSE_WAIT);
|
||
+
|
||
+ g_assert_cmpint (pseudo_tcp_socket_get_available_bytes (data.left), ==, 0);
|
||
+ g_assert_cmpint (pseudo_tcp_socket_get_available_send_space (data.left), ==,
|
||
+ 0);
|
||
+
|
||
+ expect_ack (data.right, data.right_sent, 7, 11);
|
||
+ forward_segment_rtl (&data);
|
||
+
|
||
+ expect_socket_state (data.left, TCP_FIN_WAIT_2);
|
||
+
|
||
+
|
||
+ g_assert_cmpint (pseudo_tcp_socket_get_available_bytes (data.right), ==, 3);
|
||
+
|
||
+ g_assert_cmpint (pseudo_tcp_socket_get_available_send_space (data.right), >,
|
||
+ 0);
|
||
+
|
||
+ /* Check that the data can be read */
|
||
+ g_assert_cmpint (pseudo_tcp_socket_recv (data.right, (char *) buf, sizeof (buf)), ==, 3);
|
||
+
|
||
+ /* Now the socket should be empty */
|
||
+ g_assert_cmpint (pseudo_tcp_socket_recv (data.right, (char *) buf, sizeof (buf)), ==, 0);
|
||
+
|
||
+ data_clear (&data);
|
||
+}
|
||
+
|
||
int
|
||
main (int argc, char *argv[])
|
||
{
|
||
@@ -1109,6 +1248,8 @@ main (int argc, char *argv[])
|
||
pseudotcp_close_normal_recovery3);
|
||
g_test_add_func ("/pseudotcp/close/normal/recovery4",
|
||
pseudotcp_close_normal_recovery4);
|
||
+ g_test_add_func ("/pseudotcp/close/normal/recovery-data",
|
||
+ pseudotcp_close_normal_recovery_data);
|
||
g_test_add_func ("/pseudotcp/close/simultaneous/recovery1",
|
||
pseudotcp_close_simultaneous_recovery1);
|
||
g_test_add_func ("/pseudotcp/close/simultaneous/recovery2",
|
||
@@ -1125,6 +1266,9 @@ main (int argc, char *argv[])
|
||
g_test_add_func ("/pseudotcp/close/rst-afterwards",
|
||
pseudotcp_close_rst_afterwards);
|
||
|
||
+ g_test_add_func ("/pseudotcp/close/recv-queued",
|
||
+ pseudotcp_close_recv_queued);
|
||
+
|
||
g_test_add_func ("/pseudotcp/compatibility",
|
||
pseudotcp_compatibility);
|
||
|
||
diff --git a/tests/test-pseudotcp-fuzzy.c b/tests/test-pseudotcp-fuzzy.c
|
||
index fdee222..4211248 100644
|
||
--- a/tests/test-pseudotcp-fuzzy.c
|
||
+++ b/tests/test-pseudotcp-fuzzy.c
|
||
@@ -395,7 +395,6 @@ int main (int argc, char *argv[])
|
||
GError *error = NULL;
|
||
|
||
setlocale (LC_ALL, "");
|
||
- g_type_init ();
|
||
|
||
/* Configuration. */
|
||
context = g_option_context_new ("— fuzz-test the pseudotcp socket");
|
||
diff --git a/tests/test-pseudotcp.c b/tests/test-pseudotcp.c
|
||
index e4dd613..1a8391a 100644
|
||
--- a/tests/test-pseudotcp.c
|
||
+++ b/tests/test-pseudotcp.c
|
||
@@ -259,8 +259,6 @@ int main (int argc, char *argv[])
|
||
|
||
mainloop = g_main_loop_new (NULL, FALSE);
|
||
|
||
- g_type_init ();
|
||
-
|
||
pseudo_tcp_set_debug_level (PSEUDO_TCP_DEBUG_VERBOSE);
|
||
|
||
left_closed = right_closed = FALSE;
|
||
diff --git a/tests/test-restart.c b/tests/test-restart.c
|
||
index c7f2f25..c2cbe9a 100644
|
||
--- a/tests/test-restart.c
|
||
+++ b/tests/test-restart.c
|
||
@@ -400,8 +400,6 @@ int main (void)
|
||
|
||
WSAStartup(0x0202, &w);
|
||
#endif
|
||
- g_type_init ();
|
||
- g_thread_init(NULL);
|
||
|
||
global_mainloop = g_main_loop_new (NULL, FALSE);
|
||
|
||
diff --git a/tests/test-send-recv.c b/tests/test-send-recv.c
|
||
index 55e6002..5841639 100644
|
||
--- a/tests/test-send-recv.c
|
||
+++ b/tests/test-send-recv.c
|
||
@@ -1202,8 +1202,6 @@ main (int argc, char *argv[])
|
||
WSADATA w;
|
||
WSAStartup (0x0202, &w);
|
||
#endif
|
||
- g_type_init ();
|
||
- g_thread_init (NULL);
|
||
|
||
if (!long_mode) {
|
||
/* Quick mode. Just test each of the stream APIs in reliable and
|
||
diff --git a/tests/test-socket-is-based-on.c b/tests/test-socket-is-based-on.c
|
||
new file mode 100644
|
||
index 0000000..6080fe3
|
||
--- /dev/null
|
||
+++ b/tests/test-socket-is-based-on.c
|
||
@@ -0,0 +1,122 @@
|
||
+/*
|
||
+ * This file is part of the Nice GLib ICE library.
|
||
+ *
|
||
+ * (C) 2016 Jakub Adam <jakub.adam@ktknet.cz>
|
||
+ *
|
||
+ * 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.
|
||
+ *
|
||
+ * 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 <locale.h>
|
||
+
|
||
+#include "socket.h"
|
||
+
|
||
+static NiceSocket *udp_bsd;
|
||
+static NiceSocket *tcp_active;
|
||
+static NiceSocket *pseudossl;
|
||
+static NiceSocket *udp_turn_over_tcp;
|
||
+
|
||
+static void
|
||
+socket_base_udp_bsd (void)
|
||
+{
|
||
+ g_assert (nice_socket_is_based_on (udp_bsd, udp_bsd));
|
||
+ g_assert (!nice_socket_is_based_on (udp_bsd, tcp_active));
|
||
+ g_assert (!nice_socket_is_based_on (udp_bsd, pseudossl));
|
||
+ g_assert (!nice_socket_is_based_on (udp_bsd, udp_turn_over_tcp));
|
||
+}
|
||
+
|
||
+static void
|
||
+socket_base_tcp_active (void)
|
||
+{
|
||
+ g_assert (!nice_socket_is_based_on (tcp_active, udp_bsd));
|
||
+ g_assert (nice_socket_is_based_on (tcp_active, tcp_active));
|
||
+ g_assert (!nice_socket_is_based_on (tcp_active, pseudossl));
|
||
+ g_assert (!nice_socket_is_based_on (tcp_active, udp_turn_over_tcp));
|
||
+}
|
||
+
|
||
+static void
|
||
+socket_base_pseudossl (void)
|
||
+{
|
||
+ g_assert (!nice_socket_is_based_on (pseudossl, udp_bsd));
|
||
+ g_assert (nice_socket_is_based_on (pseudossl, tcp_active));
|
||
+ g_assert (nice_socket_is_based_on (pseudossl, pseudossl));
|
||
+ g_assert (!nice_socket_is_based_on (pseudossl, udp_turn_over_tcp));
|
||
+}
|
||
+
|
||
+static void
|
||
+socket_base_udp_turn_over_tcp (void)
|
||
+{
|
||
+ g_assert (!nice_socket_is_based_on (udp_turn_over_tcp, udp_bsd));
|
||
+ g_assert (nice_socket_is_based_on (udp_turn_over_tcp, tcp_active));
|
||
+ g_assert (nice_socket_is_based_on (udp_turn_over_tcp, pseudossl));
|
||
+ g_assert (nice_socket_is_based_on (udp_turn_over_tcp, udp_turn_over_tcp));
|
||
+}
|
||
+
|
||
+int
|
||
+main (int argc, char *argv[])
|
||
+{
|
||
+ GMainLoop *mainloop = NULL;
|
||
+
|
||
+ NiceAddress addr;
|
||
+
|
||
+ setlocale (LC_ALL, "");
|
||
+ g_test_init (&argc, &argv, NULL);
|
||
+
|
||
+ mainloop = g_main_loop_new (NULL, TRUE);
|
||
+
|
||
+ nice_address_set_from_string (&addr, "127.0.0.1");
|
||
+
|
||
+ /* Standalone socket */
|
||
+ udp_bsd = nice_udp_bsd_socket_new (&addr);
|
||
+
|
||
+ /* tcp_passive -> pseudossl -> udp_turn_over_tcp */
|
||
+ tcp_active = nice_tcp_active_socket_new (g_main_loop_get_context (mainloop),
|
||
+ &addr);
|
||
+ pseudossl = nice_pseudossl_socket_new (tcp_active,
|
||
+ NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_GOOGLE);
|
||
+ udp_turn_over_tcp = nice_udp_turn_over_tcp_socket_new (pseudossl,
|
||
+ NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE);
|
||
+
|
||
+ g_test_add_func ("/socket/is-base-of/udp-bsd",
|
||
+ socket_base_udp_bsd);
|
||
+ g_test_add_func ("/socket/is-base-of/tcp-active",
|
||
+ socket_base_tcp_active);
|
||
+ g_test_add_func ("/socket/is-base-of/pseudossl",
|
||
+ socket_base_pseudossl);
|
||
+ g_test_add_func ("/socket/is-base-of/udp-turn-over-tcp",
|
||
+ socket_base_udp_turn_over_tcp);
|
||
+
|
||
+ g_test_run ();
|
||
+
|
||
+ nice_socket_free (udp_bsd);
|
||
+ nice_socket_free (udp_turn_over_tcp);
|
||
+
|
||
+ g_main_loop_unref (mainloop);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
diff --git a/tests/test-tcp.c b/tests/test-tcp.c
|
||
index dd259a4..e2a1bfd 100644
|
||
--- a/tests/test-tcp.c
|
||
+++ b/tests/test-tcp.c
|
||
@@ -88,8 +88,6 @@ main (void)
|
||
NiceAddress active_bind_addr, passive_bind_addr;
|
||
GSource *srv_listen_source, *srv_input_source, *cli_input_source;
|
||
|
||
- g_type_init ();
|
||
-
|
||
mainloop = g_main_loop_new (NULL, FALSE);
|
||
|
||
nice_address_init (&active_bind_addr);
|
||
diff --git a/tests/test-thread.c b/tests/test-thread.c
|
||
index df0b145..7493f97 100644
|
||
--- a/tests/test-thread.c
|
||
+++ b/tests/test-thread.c
|
||
@@ -211,8 +211,6 @@ int main (void)
|
||
WSADATA w;
|
||
WSAStartup(0x0202, &w);
|
||
#endif
|
||
- g_type_init ();
|
||
- g_thread_init(NULL);
|
||
|
||
lmainctx = g_main_context_new ();
|
||
rmainctx = g_main_context_new ();
|
||
@@ -291,13 +289,8 @@ int main (void)
|
||
/* step: run test the first time */
|
||
g_debug ("test-thread: TEST STARTS / running test for the 1st time");
|
||
|
||
-#if !GLIB_CHECK_VERSION(2,31,8)
|
||
- lthread = g_thread_create (mainloop_thread, lmainloop, TRUE, NULL);
|
||
- rthread = g_thread_create (mainloop_thread, rmainloop, TRUE, NULL);
|
||
-#else
|
||
lthread = g_thread_new ("lthread libnice", mainloop_thread, lmainloop);
|
||
rthread = g_thread_new ("rthread libnice", mainloop_thread, rmainloop);
|
||
-#endif
|
||
|
||
g_assert (lthread);
|
||
g_assert (rthread);
|
||
@@ -318,13 +311,9 @@ int main (void)
|
||
nice_agent_attach_recv (ragent, rs_id, 1, rdmainctx, cb_nice_recv,
|
||
GUINT_TO_POINTER (2));
|
||
|
||
-#if !GLIB_CHECK_VERSION(2,31,8)
|
||
- ldthread = g_thread_create (mainloop_thread, ldmainloop, TRUE, NULL);
|
||
- rdthread = g_thread_create (mainloop_thread, rdmainloop, TRUE, NULL);
|
||
-#else
|
||
ldthread = g_thread_new ("ldthread libnice", mainloop_thread, ldmainloop);
|
||
rdthread = g_thread_new ("rdthread libnice", mainloop_thread, rdmainloop);
|
||
-#endif
|
||
+
|
||
g_assert (ldthread);
|
||
g_assert (rdthread);
|
||
|
||
diff --git a/tests/test-turn.c b/tests/test-turn.c
|
||
new file mode 100644
|
||
index 0000000..46d1bf2
|
||
--- /dev/null
|
||
+++ b/tests/test-turn.c
|
||
@@ -0,0 +1,379 @@
|
||
+#include <stdlib.h>
|
||
+#include <stdio.h>
|
||
+#include <string.h>
|
||
+
|
||
+#include <gio/gio.h>
|
||
+#include <agent.h>
|
||
+
|
||
+static NiceComponentState global_lagent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST };
|
||
+static NiceComponentState global_ragent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST };
|
||
+static guint global_components_ready = 0;
|
||
+static gboolean global_lagent_gathering_done = FALSE;
|
||
+static gboolean global_ragent_gathering_done = FALSE;
|
||
+static int global_lagent_cands = 0;
|
||
+static int global_ragent_cands = 0;
|
||
+
|
||
+#define TURN_USER "toto"
|
||
+#define TURN_PASS "password"
|
||
+
|
||
+static gboolean timer_cb (gpointer pointer)
|
||
+{
|
||
+ g_debug ("test-turn:%s: %p", G_STRFUNC, pointer);
|
||
+
|
||
+ /* signal status via a global variable */
|
||
+
|
||
+ /* note: should not be reached, abort */
|
||
+ g_error ("ERROR: test has got stuck, aborting...");
|
||
+
|
||
+ return FALSE;
|
||
+}
|
||
+
|
||
+static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data)
|
||
+{
|
||
+ g_debug ("test-fullmode:%s: %p", G_STRFUNC, user_data);
|
||
+
|
||
+ /* XXX: dear compiler, these are for you: */
|
||
+ (void)agent; (void)stream_id; (void)component_id; (void)buf;
|
||
+
|
||
+ /*
|
||
+ * Lets ignore stun packets that got through
|
||
+ */
|
||
+ if (len < 8)
|
||
+ return;
|
||
+ if (strncmp ("12345678", buf, 8))
|
||
+ return;
|
||
+
|
||
+ if (component_id != 1)
|
||
+ return;
|
||
+
|
||
+#if 0
|
||
+ if (GPOINTER_TO_UINT (user_data) == 2) {
|
||
+ global_ragent_read += len;
|
||
+ }
|
||
+#endif
|
||
+}
|
||
+
|
||
+static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data)
|
||
+{
|
||
+ g_debug ("test-fullmode:%s: %p", G_STRFUNC, data);
|
||
+
|
||
+ if (GPOINTER_TO_UINT (data) == 1)
|
||
+ global_lagent_gathering_done = TRUE;
|
||
+ else if (GPOINTER_TO_UINT (data) == 2)
|
||
+ global_ragent_gathering_done = TRUE;
|
||
+}
|
||
+
|
||
+
|
||
+static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data)
|
||
+{
|
||
+ gboolean ready_to_connected = FALSE;
|
||
+ g_debug ("test-fullmode:%s: %p", G_STRFUNC, data);
|
||
+
|
||
+ if (GPOINTER_TO_UINT (data) == 1) {
|
||
+ if (global_lagent_state[component_id - 1] == NICE_COMPONENT_STATE_READY &&
|
||
+ state == NICE_COMPONENT_STATE_CONNECTED)
|
||
+ ready_to_connected = TRUE;
|
||
+ global_lagent_state[component_id - 1] = state;
|
||
+ } else if (GPOINTER_TO_UINT (data) == 2) {
|
||
+ if (global_ragent_state[component_id - 1] == NICE_COMPONENT_STATE_READY &&
|
||
+ state == NICE_COMPONENT_STATE_CONNECTED)
|
||
+ ready_to_connected = TRUE;
|
||
+ global_ragent_state[component_id - 1] = state;
|
||
+ }
|
||
+
|
||
+ if (state == NICE_COMPONENT_STATE_READY)
|
||
+ global_components_ready++;
|
||
+ else if (state == NICE_COMPONENT_STATE_CONNECTED && ready_to_connected)
|
||
+ global_components_ready--;
|
||
+ g_assert (state != NICE_COMPONENT_STATE_FAILED);
|
||
+
|
||
+ g_debug ("test-turn: checks READY %u.", global_components_ready);
|
||
+}
|
||
+
|
||
+static void cb_new_selected_pair(NiceAgent *agent, guint stream_id,
|
||
+ guint component_id, gchar *lfoundation, gchar* rfoundation, gpointer data)
|
||
+{
|
||
+ g_debug ("test-turn:%s: %p", G_STRFUNC, data);
|
||
+
|
||
+ if (GPOINTER_TO_UINT (data) == 1)
|
||
+ ++global_lagent_cands;
|
||
+ else if (GPOINTER_TO_UINT (data) == 2)
|
||
+ ++global_ragent_cands;
|
||
+}
|
||
+
|
||
+static void set_candidates (NiceAgent *from, guint from_stream,
|
||
+ NiceAgent *to, guint to_stream, guint component, gboolean remove_non_relay,
|
||
+ gboolean force_relay)
|
||
+{
|
||
+ GSList *cands = NULL, *i;
|
||
+
|
||
+ cands = nice_agent_get_local_candidates (from, from_stream, component);
|
||
+ if (remove_non_relay) {
|
||
+ restart:
|
||
+ for (i = cands; i; i = i->next) {
|
||
+ NiceCandidate *cand = i->data;
|
||
+ if (force_relay)
|
||
+ g_assert (cand->type == NICE_CANDIDATE_TYPE_RELAYED);
|
||
+ if (cand->type != NICE_CANDIDATE_TYPE_RELAYED) {
|
||
+ cands = g_slist_remove (cands, cand);
|
||
+ nice_candidate_free (cand);
|
||
+ goto restart;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ nice_agent_set_remote_candidates (to, to_stream, component, cands);
|
||
+
|
||
+ for (i = cands; i; i = i->next)
|
||
+ nice_candidate_free ((NiceCandidate *) i->data);
|
||
+ g_slist_free (cands);
|
||
+}
|
||
+
|
||
+static void set_credentials (NiceAgent *lagent, guint lstream,
|
||
+ NiceAgent *ragent, guint rstream)
|
||
+{
|
||
+ gchar *ufrag = NULL, *password = NULL;
|
||
+
|
||
+ nice_agent_get_local_credentials(lagent, lstream, &ufrag, &password);
|
||
+ nice_agent_set_remote_credentials (ragent, rstream, ufrag, password);
|
||
+ g_free (ufrag);
|
||
+ g_free (password);
|
||
+ nice_agent_get_local_credentials(ragent, rstream, &ufrag, &password);
|
||
+ nice_agent_set_remote_credentials (lagent, lstream, ufrag, password);
|
||
+ g_free (ufrag);
|
||
+ g_free (password);
|
||
+}
|
||
+
|
||
+static void
|
||
+run_test(guint turn_port, gboolean is_ipv6,
|
||
+ gboolean ice_udp, gboolean ice_tcp, gboolean force_relay,
|
||
+ gboolean remove_non_relay,
|
||
+ NiceRelayType turn_type)
|
||
+{
|
||
+ NiceAgent *lagent, *ragent; /* agent's L and R */
|
||
+ const gchar *localhost;
|
||
+ NiceAddress localaddr;
|
||
+ guint ls_id, rs_id;
|
||
+ gulong timer_id;
|
||
+
|
||
+ if (is_ipv6)
|
||
+ localhost = "::1";
|
||
+ else
|
||
+ localhost = "127.0.0.1";
|
||
+
|
||
+ /* step: initialize variables modified by the callbacks */
|
||
+ global_components_ready = 0;
|
||
+ global_lagent_gathering_done = FALSE;
|
||
+ global_ragent_gathering_done = FALSE;
|
||
+ global_lagent_cands = global_ragent_cands = 0;
|
||
+
|
||
+ lagent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245);
|
||
+ ragent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245);
|
||
+
|
||
+ g_object_set (G_OBJECT (lagent), "ice-tcp", ice_tcp, "ice-udp", ice_udp,
|
||
+ "force-relay", force_relay, NULL);
|
||
+ g_object_set (G_OBJECT (ragent), "ice-tcp", ice_tcp, "ice-udp", ice_udp,
|
||
+ "force-relay", force_relay, NULL);
|
||
+
|
||
+ g_object_set (G_OBJECT (lagent), "upnp", FALSE, NULL);
|
||
+ g_object_set (G_OBJECT (ragent), "upnp", FALSE, NULL);
|
||
+ nice_agent_set_software (lagent, "Test-turn, Left Agent");
|
||
+ nice_agent_set_software (ragent, "Test-turn, Right Agent");
|
||
+
|
||
+ timer_id = g_timeout_add (30000, timer_cb, NULL);
|
||
+
|
||
+
|
||
+ if (!nice_address_set_from_string (&localaddr, localhost))
|
||
+ g_assert_not_reached ();
|
||
+ nice_agent_add_local_address (lagent, &localaddr);
|
||
+ nice_agent_add_local_address (ragent, &localaddr);
|
||
+
|
||
+ g_signal_connect (G_OBJECT (lagent), "candidate-gathering-done",
|
||
+ G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER(1));
|
||
+ g_signal_connect (G_OBJECT (ragent), "candidate-gathering-done",
|
||
+ G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER (2));
|
||
+ g_signal_connect (G_OBJECT (lagent), "component-state-changed",
|
||
+ G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (1));
|
||
+ g_signal_connect (G_OBJECT (ragent), "component-state-changed",
|
||
+ G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (2));
|
||
+ g_signal_connect (G_OBJECT (lagent), "new-selected-pair",
|
||
+ G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER(1));
|
||
+ g_signal_connect (G_OBJECT (ragent), "new-selected-pair",
|
||
+ G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER (2));
|
||
+
|
||
+ g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL);
|
||
+ g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL);
|
||
+
|
||
+ ls_id = nice_agent_add_stream (lagent, 1);
|
||
+ rs_id = nice_agent_add_stream (ragent, 1);
|
||
+ g_assert (ls_id > 0);
|
||
+ g_assert (rs_id > 0);
|
||
+ nice_agent_set_relay_info(lagent, ls_id, 1,
|
||
+ localhost, turn_port, TURN_USER, TURN_PASS, turn_type);
|
||
+ nice_agent_set_relay_info(ragent, rs_id, 1,
|
||
+ localhost, turn_port, TURN_USER, TURN_PASS, turn_type);
|
||
+
|
||
+ /* Gather candidates and test nice_agent_set_port_range */
|
||
+ g_assert (nice_agent_gather_candidates (lagent, ls_id) == TRUE);
|
||
+ g_assert (nice_agent_gather_candidates (ragent, rs_id) == TRUE);
|
||
+
|
||
+ nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTP,
|
||
+ g_main_context_default (), cb_nice_recv, GUINT_TO_POINTER (1));
|
||
+ nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTP,
|
||
+ g_main_context_default (), cb_nice_recv, GUINT_TO_POINTER (2));
|
||
+
|
||
+ g_assert (global_lagent_gathering_done == FALSE);
|
||
+ g_assert (global_ragent_gathering_done == FALSE);
|
||
+ g_debug ("test-turn: Added streams, running context until 'candidate-gathering-done'...");
|
||
+ while (!global_lagent_gathering_done && !global_ragent_gathering_done)
|
||
+ g_main_context_iteration (NULL, TRUE);
|
||
+ g_assert (global_lagent_gathering_done == TRUE);
|
||
+ g_assert (global_ragent_gathering_done == TRUE);
|
||
+
|
||
+ set_credentials (lagent, ls_id, ragent, rs_id);
|
||
+
|
||
+ set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTP,
|
||
+ remove_non_relay, force_relay);
|
||
+ set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTP,
|
||
+ remove_non_relay, force_relay);
|
||
+
|
||
+ while (global_lagent_state[0] != NICE_COMPONENT_STATE_READY ||
|
||
+ global_ragent_state[0] != NICE_COMPONENT_STATE_READY)
|
||
+ g_main_context_iteration (NULL, TRUE);
|
||
+ g_assert (global_lagent_state[0] == NICE_COMPONENT_STATE_READY);
|
||
+ g_assert (global_ragent_state[0] == NICE_COMPONENT_STATE_READY);
|
||
+
|
||
+ nice_agent_remove_stream (lagent, ls_id);
|
||
+ nice_agent_remove_stream (ragent, rs_id);
|
||
+
|
||
+ g_source_remove (timer_id);
|
||
+
|
||
+ g_clear_object(&lagent);
|
||
+ g_clear_object(&ragent);
|
||
+}
|
||
+
|
||
+guint global_turn_port;
|
||
+
|
||
+static void
|
||
+udp_no_force_no_remove_udp (void)
|
||
+{
|
||
+ run_test(global_turn_port, FALSE /* is_ipv6 */,
|
||
+ TRUE /* ice_udp */,
|
||
+ FALSE /* ice_tcp */,
|
||
+ FALSE /* force_relay */,
|
||
+ FALSE /* remove_non_relay */,
|
||
+ NICE_RELAY_TYPE_TURN_UDP);
|
||
+}
|
||
+
|
||
+static void
|
||
+udp_no_force_remove_udp (void)
|
||
+{
|
||
+ run_test(global_turn_port, FALSE /* is_ipv6 */,
|
||
+ TRUE /* ice_udp */,
|
||
+ FALSE /* ice_tcp */,
|
||
+ FALSE /* force_relay */,
|
||
+ TRUE /* remove_non_relay */,
|
||
+ NICE_RELAY_TYPE_TURN_UDP);
|
||
+}
|
||
+
|
||
+static void
|
||
+udp_force_no_remove_udp (void)
|
||
+{
|
||
+ run_test(global_turn_port, FALSE /* is_ipv6 */,
|
||
+ TRUE /* ice_udp */,
|
||
+ FALSE /* ice_tcp */,
|
||
+ TRUE /* force_relay */,
|
||
+ FALSE /* remove_non_relay */,
|
||
+ NICE_RELAY_TYPE_TURN_UDP);
|
||
+}
|
||
+
|
||
+static void
|
||
+udp_no_force_no_remove_tcp (void)
|
||
+{
|
||
+ run_test(global_turn_port, FALSE /* is_ipv6 */,
|
||
+ TRUE /* ice_udp */,
|
||
+ FALSE /* ice_tcp */,
|
||
+ FALSE /* force_relay */,
|
||
+ FALSE /* remove_non_relay */,
|
||
+ NICE_RELAY_TYPE_TURN_TCP);
|
||
+}
|
||
+
|
||
+static void
|
||
+udp_no_force_remove_tcp (void)
|
||
+{
|
||
+ run_test(global_turn_port, FALSE /* is_ipv6 */,
|
||
+ TRUE /* ice_udp */,
|
||
+ FALSE /* ice_tcp */,
|
||
+ FALSE /* force_relay */,
|
||
+ TRUE /* remove_non_relay */,
|
||
+ NICE_RELAY_TYPE_TURN_TCP);
|
||
+}
|
||
+
|
||
+static void
|
||
+udp_force_no_remove_tcp (void)
|
||
+{
|
||
+ run_test(global_turn_port, FALSE /* is_ipv6 */,
|
||
+ TRUE /* ice_udp */,
|
||
+ FALSE /* ice_tcp */,
|
||
+ TRUE /* force_relay */,
|
||
+ FALSE /* remove_non_relay */,
|
||
+ NICE_RELAY_TYPE_TURN_TCP);
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+
|
||
+
|
||
+int
|
||
+main (int argc, char **argv)
|
||
+{
|
||
+ GSubprocess *sp;
|
||
+ GError *error = NULL;
|
||
+ gchar portstr[10];
|
||
+ int ret;
|
||
+ gchar *out_str = NULL;
|
||
+ gchar *err_str = NULL;
|
||
+
|
||
+ g_test_init (&argc, &argv, NULL);
|
||
+
|
||
+ global_turn_port = g_random_int_range (10000, 60000);
|
||
+ snprintf(portstr, 9, "%u", global_turn_port);
|
||
+
|
||
+ if (g_spawn_command_line_sync ("turnserver --help", &out_str, &err_str, NULL,
|
||
+ NULL) && err_str) {
|
||
+ if (!strstr(err_str, "--user")) {
|
||
+ g_print ("rfc5766-turn-server not installed, skipping turn test\n");
|
||
+ return 0;
|
||
+ }
|
||
+ } else {
|
||
+ g_print ("rfc5766-turn-server not installed, skipping turn test\n");
|
||
+ return 0;
|
||
+ }
|
||
+ g_free (err_str);
|
||
+ g_free (out_str);
|
||
+
|
||
+ sp = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_SILENCE, &error,
|
||
+ "turnserver",
|
||
+ "--user", "toto:0xaae440b3348d50265b63703117c7bfd5",
|
||
+ "--realm", "realm",
|
||
+ "--listening-port", portstr,
|
||
+ NULL);
|
||
+
|
||
+ g_test_add_func ("/nice/turn/udp", udp_no_force_no_remove_udp);
|
||
+ g_test_add_func ("/nice/turn/udp/remove_non_turn",
|
||
+ udp_no_force_remove_udp);
|
||
+ g_test_add_func ("/nice/turn/udp/force_relay",
|
||
+ udp_force_no_remove_udp);
|
||
+ g_test_add_func ("/nice/turn/udp/over-tcp", udp_no_force_no_remove_tcp);
|
||
+ g_test_add_func ("/nice/turn/udp/over-tcp/remove_non_turn",
|
||
+ udp_no_force_remove_tcp);
|
||
+ g_test_add_func ("/nice/turn/udp/over-tcp/force_relay",
|
||
+ udp_force_no_remove_tcp);
|
||
+
|
||
+ ret = g_test_run ();
|
||
+
|
||
+ g_subprocess_force_exit (sp);
|
||
+ g_subprocess_wait (sp, NULL, NULL);
|
||
+ g_clear_object (&sp);
|
||
+
|
||
+ return ret;
|
||
+}
|
||
diff --git a/tests/test.c b/tests/test.c
|
||
index 31a9fc7..a92b33c 100644
|
||
--- a/tests/test.c
|
||
+++ b/tests/test.c
|
||
@@ -75,9 +75,6 @@ main (void)
|
||
|
||
nice_address_init (&addr_local);
|
||
nice_address_init (&addr_remote);
|
||
- g_type_init ();
|
||
-
|
||
- g_thread_init(NULL);
|
||
|
||
g_assert (nice_address_set_from_string (&addr_local, "127.0.0.1"));
|
||
g_assert (nice_address_set_from_string (&addr_remote, "127.0.0.1"));
|
||
diff --git a/win32/vs9/libnice.def b/win32/vs9/libnice.def
|
||
deleted file mode 100644
|
||
index 7065330..0000000
|
||
--- a/win32/vs9/libnice.def
|
||
+++ /dev/null
|
||
@@ -1,137 +0,0 @@
|
||
-LIBRARY libnice
|
||
-
|
||
-EXPORTS
|
||
-
|
||
-nice_address_copy_to_sockaddr
|
||
-nice_address_dup
|
||
-nice_address_equal
|
||
-nice_address_equal_no_port
|
||
-nice_address_free
|
||
-nice_address_get_port
|
||
-nice_address_init
|
||
-nice_address_ip_version
|
||
-nice_address_is_private
|
||
-nice_address_is_valid
|
||
-nice_address_new
|
||
-nice_address_set_from_sockaddr
|
||
-nice_address_set_from_string
|
||
-nice_address_set_ipv4
|
||
-nice_address_set_ipv6
|
||
-nice_address_set_port
|
||
-nice_address_to_string
|
||
-nice_agent_add_local_address
|
||
-nice_agent_add_stream
|
||
-nice_agent_attach_recv
|
||
-nice_agent_forget_relays
|
||
-nice_agent_gather_candidates
|
||
-nice_agent_generate_local_candidate_sdp
|
||
-nice_agent_generate_local_sdp
|
||
-nice_agent_generate_local_stream_sdp
|
||
-nice_agent_get_default_local_candidate
|
||
-nice_agent_get_local_candidates
|
||
-nice_agent_get_local_credentials
|
||
-nice_agent_get_remote_candidates
|
||
-nice_agent_get_selected_pair
|
||
-nice_agent_get_selected_socket
|
||
-nice_agent_get_stream_name
|
||
-nice_agent_get_type
|
||
-nice_agent_new
|
||
-nice_agent_new_reliable
|
||
-nice_agent_parse_remote_candidate_sdp
|
||
-nice_agent_parse_remote_sdp
|
||
-nice_agent_parse_remote_stream_sdp
|
||
-nice_agent_remove_stream
|
||
-nice_agent_restart
|
||
-nice_agent_send
|
||
-nice_agent_set_port_range
|
||
-nice_agent_set_relay_info
|
||
-nice_agent_set_remote_candidates
|
||
-nice_agent_set_remote_credentials
|
||
-nice_agent_set_local_credentials
|
||
-nice_agent_set_selected_pair
|
||
-nice_agent_set_selected_remote_candidate
|
||
-nice_agent_set_software
|
||
-nice_agent_set_stream_name
|
||
-nice_agent_set_stream_tos
|
||
-nice_candidate_copy
|
||
-nice_candidate_free
|
||
-nice_candidate_new
|
||
-nice_component_state_to_string
|
||
-nice_debug_disable
|
||
-nice_debug_enable
|
||
-nice_interfaces_get_ip_for_interface
|
||
-nice_interfaces_get_local_interfaces
|
||
-nice_interfaces_get_local_ips
|
||
-pseudo_tcp_set_debug_level
|
||
-pseudo_tcp_socket_close
|
||
-pseudo_tcp_socket_connect
|
||
-pseudo_tcp_socket_get_error
|
||
-pseudo_tcp_socket_get_next_clock
|
||
-pseudo_tcp_socket_new
|
||
-pseudo_tcp_socket_notify_clock
|
||
-pseudo_tcp_socket_notify_mtu
|
||
-pseudo_tcp_socket_notify_packet
|
||
-pseudo_tcp_socket_recv
|
||
-pseudo_tcp_socket_send
|
||
-stun_agent_build_unknown_attributes_error
|
||
-stun_agent_default_validater
|
||
-stun_agent_finish_message
|
||
-stun_agent_forget_transaction
|
||
-stun_agent_init
|
||
-stun_agent_init_error
|
||
-stun_agent_init_indication
|
||
-stun_agent_init_request
|
||
-stun_agent_init_response
|
||
-stun_agent_set_software
|
||
-stun_agent_validate
|
||
-stun_debug_disable
|
||
-stun_debug_enable
|
||
-stun_debug
|
||
-stun_debug_bytes
|
||
-stun_hash_creds
|
||
-stun_message_append
|
||
-stun_message_append32
|
||
-stun_message_append64
|
||
-stun_message_append_addr
|
||
-stun_message_append_bytes
|
||
-stun_message_append_error
|
||
-stun_message_append_flag
|
||
-stun_message_append_string
|
||
-stun_message_append_xor_addr
|
||
-stun_message_append_xor_addr_full
|
||
-stun_message_find
|
||
-stun_message_find32
|
||
-stun_message_find64
|
||
-stun_message_find_addr
|
||
-stun_message_find_error
|
||
-stun_message_find_flag
|
||
-stun_message_find_string
|
||
-stun_message_find_xor_addr
|
||
-stun_message_find_xor_addr_full
|
||
-stun_message_get_class
|
||
-stun_message_get_method
|
||
-stun_message_has_attribute
|
||
-stun_message_has_cookie
|
||
-stun_message_id
|
||
-stun_message_init
|
||
-stun_message_length
|
||
-stun_message_validate_buffer_length
|
||
-stun_optional
|
||
-stun_strerror
|
||
-stun_timer_refresh
|
||
-stun_timer_remainder
|
||
-stun_timer_start
|
||
-stun_timer_start_reliable
|
||
-stun_usage_bind_create
|
||
-stun_usage_bind_keepalive
|
||
-stun_usage_bind_process
|
||
-stun_usage_bind_run
|
||
-stun_usage_ice_conncheck_create
|
||
-stun_usage_ice_conncheck_create_reply
|
||
-stun_usage_ice_conncheck_priority
|
||
-stun_usage_ice_conncheck_process
|
||
-stun_usage_ice_conncheck_use_candidate
|
||
-stun_usage_turn_create
|
||
-stun_usage_turn_create_refresh
|
||
-stun_usage_turn_process
|
||
-stun_usage_turn_refresh_process
|