Open malytomas opened 1 year ago
1. When do I call juice_get_local_description? Can I call it immediately after juice_create or should I give the agent some time for connecting to the stun server?
You can do both: either you call it before gathering, then you have to send candidates to the remote agent, or you call it when gathering is done, then you only need to send the description (see the notrickle
test).
2. Can I call juice_get_local_description on both agents before calling any juice_set_remote_description? Or do I always have to wait with one agent to receive description from the first agent?
Yes you can, the library will detect a role conflit and resolve it, as both agents initiate the connection. Protocols relying on ICE (SIP, WebRTC, etc) typically have a form of offer/answer as one peer always calls the other one.
3. Can or should I call juice_set_remote_description repeatedly on same agent? Should I repeatedly exchange descriptions between agents?
No, only once.
4. When do I call juice_gather_candidates? Do I always call it immediately after first juice_set_remote_description, or are there any reasons to delay it or not to call it?
You should call it as soon as possible, there is no reason to delay it. However, you can call juice_get_local_description()
before or after it, see answer to 1 above.
5. After the agent is completed, do I have to use juice_send for my connection, or can I use juice_get_selected_addresses and create new socket for my communication?
You must use juice_send()
as the connection is only established for the local port the agent is bound to. Also, the agent has to handle background tasks like keepalives.
6. Which, if any, juice functions block?
None!
7. Are there any observable differences for me for using different concurrency models?
If you create multiple agents in the same program, there are of course differences in terms of performance and resource usage. Otherwise, MUX
introduces some limitation: you might experience reconnection issues if both local and remote agents use MUX
(it is designed for servers, not clients).
Thanks for such detailed answer. I have some followup questions:
Rewriting all of my networking to use juice_send would be a major painpoint. Would it be possible to extract the socket from the agent to reuse it in my code?
Alternatively, according to my initial experiments, it seems possible to juice_get_selected_addresses, then destroy the agent, create new socket, bind, connect, and it seems to work. Does destroying the agent have any side effects, such as sending icmp or other packets etc, which would need to be stopped?
Are the keepalives from the agent special in some way? Is it sufficient to send my own?
If I understand it correctly, both the JUICE_CONCURRENCY_MODE_POLL and JUICE_CONCURRENCY_MODE_THREAD cause each agent to have its own socket, therefore making it safe to extract it or otherwise reuse, right?
On slightly different topic. How reliable is ICE in general or juice in particular, without turn server? I made some tests last week with unsatisfying results so far.
I appreciate your help again ;)
8. Rewritiing all of my networking to use juice_send would be a major painpoint. Would it be possible to _extract_ the socket from the agent to reuse it in my code?
It would break compatibility with the ICE protocol and it feels a bit hacky, but if you use a modified libjuice on both sides and don't use TURN it could work.
9. Alternatively, according to my initial experiments, it seems possible to juice_get_selected_addresses, then destroy the agent, create new socket, bind, connect, and it seems to work. Does destroying the agent have any side effects, such as sending icmp or other packets etc, which would need to be stopped?
This does not work in general as the local selected address is the local address seen by the remote peer, which will often be a NAT public-facing address. There is absolutely no guarantee that the socket is bound to the same port in the case of NAT traversal.
Also, destroying the agent does not send any packet but you may lose incoming packets and the other peer might receive ICMP port unreachable messages, since you can't extract the socket synchronously on both sides. I don't recommend doing that.
10. Are the keepalives from the agent special in some way? Is it sufficient to send my own?
Any UDP packet will keep the path alive. ICE agents require the remote agent to answer their consent refresh requests even after connection otherwise they may time out.
11. If I understand it correctly, both the JUICE_CONCURRENCY_MODE_POLL and JUICE_CONCURRENCY_MODE_THREAD cause each agent to have its own socket, therefore making it safe to _extract_ it or otherwise reuse, right?
Yes they do.
12. On slightly different topic. How reliable is ICE in general or juice in particular, without turn server? I made some tests last week with unsatisfying results so far. * localhost (both clients on one computer) - succeeded * lan (both computers connected to same router) - succeeded * lan (windows to linux) - failed (this might be my mistake somewhere) * one computer connected to home isp and second computer connected through mobile network - failed * my home computer to friends computer in another country - failed * two friends in same household (i am not sure about their network setup) - failed (note that by failed I mean the ice agent status failed)
All these situations should typically connect fine, only mobile to mobile is expected to often fail (the situation where P2P connection is impossible is when both peers are behind endpoint-dependent NATs, aka "symmetric" NATs, which mobile ISPs often use).
Check the STUN server is reachable, that all candidates are transmitted properly (there should be a "srflx" one), and that descriptions are exchanged fast enough (the whole exchange must take less than 10s or so).
Thanks again for all the answers!! ;) I have few more questions, please, bear with me ;)
Does ICE (using juice_send) add any additional bytes to the packets? If so, what MTU change should I consider for it? Also, I assume that juice_send works with binary data, right? The receive callback would provide bit-exact copy of the data sent, right? (assuming normal udp restrictions)
What thread is cb_recv called in? Are all callbacks called in the same thread?
Do you have any information on license or other conditions for using google stun servers? I have not found anything.
Do both clients need to connect to same stun server?
Your answers are greatly appreciated. Thanks.
13. Does ICE (using juice_send) add any additional bytes to the packets? If so, what MTU change should I consider for it? Also, I assume that juice_send works with binary data, right? The receive callback would provide bit-exact copy of the data sent, right? (assuming normal udp restrictions)
It doesn't add additional bytes except when relaying through a TURN server (in this case it adds 4 bytes). The data is indeed always considered as binary and unchanged.
14. What thread is cb_recv called in? Are all callbacks called in the same thread?
Yes they are called in the same thread. The thread is either shared between connections with concurrency modes POLL
and MUX
or dedicated to the connection with concurrency mode THREAD
.
15. Do you have any information on license or other conditions for using google stun servers? I have not found anything.
I think Google STUN servers are primarily there for Google products and developers ended up using them as a free service, but without any form of SLA. As far as I know there is no guarantee, Google could decide to change them or put them offline at some point. Additionally, the servers are blacklisted in China, which can be an issue. I'd recommend that you use your own server.
16. Do both clients need to connect to same stun server?
No, clients can use different STUN servers.
Several questions on how to use the library (as an agent only):
When do I call juice_get_local_description? Can I call it immediately after juice_create or should I give the agent some time for connecting to the stun server?
Can I call juice_get_local_description on both agents before calling any juice_set_remote_description? Or do I always have to wait with one agent to receive description from the first agent?
Can or should I call juice_set_remote_description repeatedly on same agent? Should I repeatedly exchange descriptions between agents?
When do I call juice_gather_candidates? Do I always call it immediately after first juice_set_remote_description, or are there any reasons to delay it or not to call it?
After the agent is completed, do I have to use juice_send for my connection, or can I use juice_get_selected_addresses and create new socket for my communication?
Which, if any, juice functions block?
Are there any observable differences for me for using different concurrency models?
Thanks for your help ;)