forked from quocdat1804/linphone_ios_sdk_spm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
delay_ice_for_external_callback.patch
403 lines (385 loc) · 17 KB
/
delay_ice_for_external_callback.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
diff --git a/liblinphone/coreapi/private_functions.h b/liblinphone/coreapi/private_functions.h
index 7dc2b0f15..85ee93f7a 100644
--- a/liblinphone/coreapi/private_functions.h
+++ b/liblinphone/coreapi/private_functions.h
@@ -646,6 +646,7 @@ void linphone_core_notify_auth_info_requested(LinphoneCore *lc, const char *real
void linphone_core_notify_authentication_requested(LinphoneCore *lc, LinphoneAuthInfo *auth_info, LinphoneAuthMethod method);
void linphone_core_notify_call_log_updated(LinphoneCore *lc, LinphoneCallLog *newcl);
void linphone_core_notify_call_id_updated(LinphoneCore *lc, const char*previous, const char *current);
+void linphone_core_notify_delay_ice_callback(LinphoneCore *lc);
void linphone_core_notify_text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message);
void linphone_core_notify_message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message);
void linphone_core_notify_messages_received(LinphoneCore *lc, LinphoneChatRoom *room, const bctbx_list_t *messages);
diff --git a/liblinphone/coreapi/vtables.c b/liblinphone/coreapi/vtables.c
index 93fd52e99..fc4cb862b 100644
--- a/liblinphone/coreapi/vtables.c
+++ b/liblinphone/coreapi/vtables.c
@@ -190,6 +190,12 @@ void linphone_core_notify_call_id_updated(LinphoneCore *lc, const char*previous,
NOTIFY_IF_EXIST(call_id_updated, lc, previous, current);
cleanup_dead_vtable_refs(lc);
}
+
+void linphone_core_notify_delay_ice_callback(LinphoneCore *lc) {
+ NOTIFY_IF_EXIST(delay_ice_callback, lc);
+ cleanup_dead_vtable_refs(lc);
+}
+
#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
#pragma GCC diagnostic push
#endif
diff --git a/liblinphone/coreapi/linphonecore.c b/liblinphone/coreapi/linphonecore.c
index 51611dbdf..878750453 100644
--- a/liblinphone/coreapi/linphonecore.c
+++ b/liblinphone/coreapi/linphonecore.c
@@ -685,6 +685,30 @@ void linphone_core_cbs_set_account_registration_state_changed(LinphoneCoreCbs *c
cbs->vtable->account_registration_state_changed = cb;
}
+// TN patch
+LinphoneCoreCbsDelayIceCallbackCb linphone_core_cbs_get_delay_ice_callback(LinphoneCoreCbs *cbs) {
+ return cbs->vtable->delay_ice_callback;
+}
+
+void linphone_core_cbs_set_delay_ice_callback(LinphoneCoreCbs *cbs, LinphoneCoreCbsDelayIceCallbackCb cb) {
+ cbs->vtable->delay_ice_callback = cb;
+}
+
+std::queue<std::function<LinphoneStatus()>> MediaSessionPrivate_iceDeferedPrepareTasks;
+
+void MediaSessionPrivate_runIcePrepareTasks() {
+ while (!MediaSessionPrivate_iceDeferedPrepareTasks.empty()) {
+ const auto task = MediaSessionPrivate_iceDeferedPrepareTasks.front();
+ task(); // Ok to discard result?
+ MediaSessionPrivate_iceDeferedPrepareTasks.pop();
+ }
+}
+
+void linphone_core_mark_delay_ice_as_completed(LinphoneCore */*core*/) {
+ MediaSessionPrivate_runIcePrepareTasks();
+}
+// TN patch
+
void lc_callback_obj_init(LCCallbackObj *obj,LinphoneCoreCbFunc func,void* ud) {
obj->_func=func;
obj->_user_data=ud;
diff --git a/liblinphone/include/linphone/api/c-nat-policy.h b/liblinphone/include/linphone/api/c-nat-policy.h
index f72acba9d..05d5c164f 100644
--- a/liblinphone/include/linphone/api/c-nat-policy.h
+++ b/liblinphone/include/linphone/api/c-nat-policy.h
@@ -289,6 +289,24 @@ LINPHONE_PUBLIC bool_t linphone_nat_policy_tls_turn_transport_enabled(const Linp
*/
LINPHONE_PUBLIC LinphoneCore *linphone_nat_policy_get_core(const LinphoneNatPolicy *policy);
+// TN patch
+
+/**
+ * Tells whether the delay ICE feature is enabled.
+ * @param policy #LinphoneNatPolicy object @notnil
+ * @return Boolean value telling whether the delay ICE feature is enabled.
+ */
+bool_t linphone_nat_policy_delay_ice_for_external_callback_enabled(const LinphoneNatPolicy *policy);
+
+/**
+ * Tells whether the delay ICE feature is enabled.
+ * @param policy #LinphoneNatPolicy object @notnil
+ * @param enable Boolean value telling whether the delay ICE feature is enabled.
+ */
+void linphone_nat_policy_enable_delay_ice_for_external_callback(LinphoneNatPolicy *policy, bool_t enable);
+
+// TN patch
+
/**
* @}
*/
diff --git a/liblinphone/include/linphone/callbacks.h b/liblinphone/include/linphone/callbacks.h
index 4b17952f8..a98f364c5 100644
--- a/liblinphone/include/linphone/callbacks.h
+++ b/liblinphone/include/linphone/callbacks.h
@@ -127,6 +127,15 @@ typedef void (*LinphoneCoreCbsRegistrationStateChangedCb)(LinphoneCore *core, Li
*/
typedef LinphoneCoreCbsRegistrationStateChangedCb LinphoneCoreRegistrationStateChangedCb;
+// TN patch
+/**
+ * Delay ICE callback
+ * @param core the #LinphoneCore @notnil
+ * @ingroup Proxies
+ */
+typedef void (*LinphoneCoreCbsDelayIceCallbackCb)(LinphoneCore *core);
+// TN patch
+
/**
* Report status change for a friend previously added to the #LinphoneCore with linphone_core_add_friend().
* @param core #LinphoneCore object @notnil
diff --git a/liblinphone/include/linphone/core.h b/include/liblinphone/linphone/core.h
index 76892c5cb..596859c44 100644
--- a/liblinphone/include/linphone/core.h
+++ b/liblinphone/include/linphone/core.h
@@ -295,6 +295,9 @@ typedef struct _LinphoneCoreVTable {
LinphoneCoreCbsImeeUserRegistrationCb imee_user_registration;
LinphoneCoreCbsChatRoomExhumedCb chat_room_exhumed;
LinphoneCoreCbsAccountRegistrationStateChangedCb account_registration_state_changed;
+ // TN patch
+ LinphoneCoreCbsDelayIceCallbackCb delay_ice_callback;
+ // TN patch
LinphoneCoreCbsConferenceInfoReceivedCb conference_info_received;
LinphoneCoreCbsPushNotificationReceivedCb push_notification_received;
LinphoneCoreCbsPreviewDisplayErrorOccurredCb preview_display_error_occurred;
@@ -1251,6 +1254,30 @@ linphone_core_cbs_set_account_registration_state_changed(LinphoneCoreCbs *cbs,
LINPHONE_PUBLIC LinphoneCoreCbsAccountRegistrationStateChangedCb
linphone_core_cbs_get_account_registration_state_changed(LinphoneCoreCbs *cbs);
+// TN patch
+/*
+ * Set the delay ICE callback.
+ * @param cbs #LinphoneCoreCbs object. @notnil
+ * @param cb The delay ICE callback to be used.
+ */
+LINPHONE_PUBLIC void
+linphone_core_cbs_set_delay_ice_callback(LinphoneCoreCbs *cbs, LinphoneCoreCbsDelayIceCallbackCb cb);
+
+/**
+ * Get the delay ICE callback.
+ * @param cbs #LinphoneCoreCbs object. @notnil
+ * @return The current delay ICE callback.
+ */
+LINPHONE_PUBLIC LinphoneCoreCbsDelayIceCallbackCb linphone_core_cbs_get_delay_ice_callback(LinphoneCoreCbs *cbs);
+
+/**
+ * Marks delay ICE as completed.
+ * @param cbs #LinphoneCore object. @notnil
+ * @ingroup misc
+ */
+LINPHONE_PUBLIC void linphone_core_mark_delay_ice_as_completed(LinphoneCore *core);
+// TN patch
+
/**
* @}
**/
diff --git a/liblinphone/src/c-wrapper/api/c-nat-policy.cpp b/liblinphone/src/c-wrapper/api/c-nat-policy.cpp
index 10b1b48dd..0805bdc8c 100644
--- a/liblinphone/src/c-wrapper/api/c-nat-policy.cpp
+++ b/liblinphone/src/c-wrapper/api/c-nat-policy.cpp
@@ -167,3 +167,13 @@ const char * linphone_nat_policy_get_nat_v6_address(const LinphoneNatPolicy *pol
void linphone_nat_policy_set_nat_v6_address(LinphoneNatPolicy *policy, const char *v6_address){
NatPolicy::toCpp(policy)->setNatV6Address(L_C_TO_STRING(v6_address));
}
+
+// TN patch
+bool_t linphone_nat_policy_delay_ice_for_external_callback_enabled(const LinphoneNatPolicy *policy) {
+ return NatPolicy::toCpp(policy)->delayIceEnabled() ? TRUE : FALSE;
+}
+
+void linphone_nat_policy_enable_delay_ice_for_external_callback(LinphoneNatPolicy *policy, bool_t enable){
+ NatPolicy::toCpp(policy)->enableDelayIce(!!enable);
+}
+// TN patch
diff --git a/liblinphone/src/conference/session/media-session.cpp b/liblinphone/src/conference/session/media-session.cpp
index fce30a5bc..1824b478b 100644
--- a/liblinphone/src/conference/session/media-session.cpp
+++ b/liblinphone/src/conference/session/media-session.cpp
@@ -57,6 +57,10 @@
#include "conference_private.h"
#include "private.h"
+// TN patch
+extern std::queue<std::function<LinphoneStatus()>> MediaSessionPrivate_iceDeferedPrepareTasks;
+// TN patch
+
using namespace std;
LINPHONE_BEGIN_NAMESPACE
@@ -3723,10 +3727,41 @@ void MediaSessionPrivate::reinviteToRecoverFromConnectionLoss() {
L_Q();
lInfo() << "MediaSession [" << q
<< "] is going to be updated (reINVITE) in order to recover from lost connectivity";
+
+ // TN patch
+ auto deferredTask = [this]() -> LinphoneStatus {
+
+ L_Q();
+ lInfo() << "MediaSessionPrivate::reinviteToRecoverFromConnectionLoss() -> deferredTask()";
+
+ const LinphoneNatPolicy *natPolicy = linphone_core_get_nat_policy(q->getCore()->getCCore());
+
+ if (natPolicy) {
+ LinphoneNatPolicy *newNatPolicy = linphone_nat_policy_clone(natPolicy);
+ q->setNatPolicy(newNatPolicy);
+ linphone_nat_policy_unref(newNatPolicy);
+ }
+
selectOutgoingIpVersion();
getStreamsGroup().getIceService().resetSession();
MediaSessionParams newParams(*getParams());
q->update(&newParams, CallSession::UpdateMethod::Invite, q->isCapabilityNegotiationEnabled());
+
+ return 0;
+ };
+
+ lInfo() << "MediaSessionPrivate::reinviteToRecoverFromConnectionLoss() -> linphone_nat_policy_delay_ice_for_external_callback_enabled=" << (int)linphone_nat_policy_delay_ice_for_external_callback_enabled(natPolicy);
+
+ if (linphone_nat_policy_delay_ice_for_external_callback_enabled(natPolicy)) {
+ lInfo() << "MediaSessionPrivate::reinviteToRecoverFromConnectionLoss() -> linphone_core_notify_delay_ice_callback()";
+
+ ::MediaSessionPrivate_iceDeferedPrepareTasks.push(deferredTask);
+ LinphoneCore *core = q->getCore()->getCCore();
+ linphone_core_notify_delay_ice_callback(core);
+ } else {
+ deferredTask();
+ }
+ // TN patch
}
void MediaSessionPrivate::repairByInviteWithReplaces() {
@@ -4629,6 +4664,8 @@ LinphoneStatus MediaSession::update(const MediaSessionParams *msp, const UpdateM
return res;
};
+ lInfo() << "MediaSessionPrivate::update() -> ice=" << (int)linphone_nat_policy_ice_enabled(d->natPolicy) << ", turn=" << (int)linphone_nat_policy_turn_enabled(d->natPolicy) << ", tcp_turn=" << (int)linphone_nat_policy_tcp_turn_transport_enabled(d->natPolicy);
+
const auto preparingStreams = d->getStreamsGroup().prepare();
// reINVITE sent after full state must be sent after ICE negotiations are completed if ICE is enabled
if (linphone_nat_policy_ice_enabled(d->natPolicy) && preparingStreams) {
diff --git a/liblinphone/src/nat/ice-service.cpp b/liblinphone/src/nat/ice-service.cpp
index 9cae3ff04..3f8c9c384 100644
--- a/liblinphone/src/nat/ice-service.cpp
+++ b/liblinphone/src/nat/ice-service.cpp
@@ -251,6 +251,8 @@ LinphoneCore *IceService::getCCore()const{
}
int IceService::gatherLocalCandidates(){
+ lInfo() << "IceService::gatherLocalCandidates()";
+
list<string> localAddrs = IfAddrs::fetchLocalAddresses();
bool ipv6Allowed = linphone_core_ipv6_enabled(getCCore());
const auto & mediaLocalIp = getMediaSessionPrivate().getMediaLocalIp();
@@ -332,6 +334,9 @@ int IceService::gatherIceCandidates () {
int err = 0;
LinphoneNatPolicy *cNatPolicy = getMediaSessionPrivate().getNatPolicy();
+
+ lInfo() << "IceService::gatherIceCandidates() -> ice=" << (int)linphone_nat_policy_ice_enabled(cNatPolicy) << ", turn=" << (int)linphone_nat_policy_turn_enabled(cNatPolicy) << ", tcp_turn=" << (int)linphone_nat_policy_tcp_turn_transport_enabled(cNatPolicy);
+
NatPolicy *natPolicy = cNatPolicy ? NatPolicy::toCpp(cNatPolicy) : nullptr;
if (natPolicy && natPolicy->stunServerActivated()) {
ai = natPolicy->getStunServerAddrinfo();
diff --git a/liblinphone/src/nat/nat-policy.cpp b/liblinphone/src/nat/nat-policy.cpp
index 275731bdb..f6cbdc53e 100644
--- a/liblinphone/src/nat/nat-policy.cpp
+++ b/liblinphone/src/nat/nat-policy.cpp
@@ -71,8 +71,9 @@ NatPolicy::NatPolicy(const NatPolicy &other): HybridObject<LinphoneNatPolicy, Na
mIceEnabled = other.mIceEnabled;
mUpnpEnabled = other.mUpnpEnabled;
mTurnUdpEnabled = other.mTurnUdpEnabled;
- mTurnTcpEnabled = false;
- mTurnTlsEnabled = false;
+ mTurnTcpEnabled = other.mTurnTcpEnabled;
+ mTurnTlsEnabled = other.mTurnTlsEnabled;
+ mDelayIceEnabled = other.mDelayIceEnabled;
}
NatPolicy::~NatPolicy(){
@@ -151,6 +152,7 @@ void NatPolicy::clear(){
mTurnUdpEnabled = false;
mTurnTcpEnabled = false;
mTurnTlsEnabled = false;
+ mDelayIceEnabled = false;
}
void NatPolicy::setStunServer(const std::string &stunServer){
diff --git a/liblinphone/src/nat/nat-policy.h b/liblinphone/src/nat/nat-policy.h
index 9a4180e76..dff92f802 100644
--- a/liblinphone/src/nat/nat-policy.h
+++ b/liblinphone/src/nat/nat-policy.h
@@ -76,6 +76,9 @@ public:
void setUserData(void *d){ mUserData = d ;}
void *getUserData()const{ return mUserData; }
+ void enableDelayIce(bool enable) { mDelayIceEnabled = enable; }
+ bool delayIceEnabled() const { return mDelayIceEnabled; }
+
const std::string &getRef()const{ return mRef; }
const struct addrinfo * getStunServerAddrinfo();
@@ -106,6 +109,7 @@ private:
bool mTurnUdpEnabled = false;
bool mTurnTcpEnabled = false;
bool mTurnTlsEnabled = false;
+ bool mDelayIceEnabled = false;
};
LINPHONE_END_NAMESPACE
diff --git a/mediastreamer2/src/voip/ice.c b/mediastreamer2/src/voip/ice.c
index d6b61d53..7419d357 100644
--- a/mediastreamer2/src/voip/ice.c
+++ b/mediastreamer2/src/voip/ice.c
@@ -996,8 +996,46 @@ static void ice_check_list_add_stun_server_request(IceCheckList *cl, IceStunServ
cl->stun_server_requests = bctbx_list_append(cl->stun_server_requests, request);
}
+// TN patch
+static void clear_turn_state(RtpTransport *rtptp, MSTurnContext *context) {
+ if (!rtptp || !context) {
+ return;
+ }
+
+ if (context->turn_tcp_client) {
+ // TODO: Currently this code just nulls the ptr to the last TURN client but notably
+ // does NOT free the memory.
+ //
+ // This is because there is another thread also using the client to send RTP,
+ // so this is tricky to sync properly. Additionally just just trying _set_endpoint
+ // to null stop that thread leads to some one-way audio issues during the call,
+ // which does not seem easy to fix.
+ //
+ // However just nulling the ptr seems to work without issue, and allow reconnects
+ // still using ICE and TCP-TURN, but we leak memory :(
+ //
+ // This is the minimal code needed to stop the RTP and free the TURN client
+ // meta_rtp_transport_set_endpoint(rtptp, NULL);
+ // ms_turn_tcp_client_destroy(context->turn_tcp_client);
+
+ (void)rtptp;
+ context->turn_tcp_client = NULL;
+ }
+
+ // clear all TURN state to avoid stale nonce error
+#define FREE_AND_NULL_VAR(var) do { ms_free(var); var = NULL; } while (0)
+ FREE_AND_NULL_VAR(context->realm);
+ FREE_AND_NULL_VAR(context->nonce);
+ FREE_AND_NULL_VAR(context->username);
+ FREE_AND_NULL_VAR(context->password);
+ FREE_AND_NULL_VAR(context->ha1);
+}
+// TN patch
+
static bool_t ice_check_list_gather_candidates(IceCheckList *cl, Session_Index *si)
{
+ ms_debug("ice_check_list_gather_candidates()");
+
IceStunServerRequest *request;
RtpTransport *rtptp=NULL;
MSTimeSpec curtime = ice_current_time();
@@ -1008,15 +1046,20 @@ static bool_t ice_check_list_gather_candidates(IceCheckList *cl, Session_Index *
cl->gathering_candidates = TRUE;
cl->gathering_start_time = curtime;
rtp_session_get_transports(cl->rtp_session,&rtptp,NULL);
+
if (rtptp) {
+
struct sockaddr *sa = (struct sockaddr *)&cl->rtp_session->rtp.gs.loc_addr;
if (cl->session->turn_enabled) {
+ // TN patch - clear TURN state due to stale nonce and sockets
+ clear_turn_state(rtptp, cl->rtp_turn_context);
+
/* Define the RTP endpoint that will perform STUN encapsulation/decapsulation for TURN data */
meta_rtp_transport_set_endpoint(rtptp, ms_turn_context_create_endpoint(cl->rtp_turn_context));
ms_turn_context_set_server_addr(cl->rtp_turn_context, (struct sockaddr *)&cl->session->ss, cl->session->ss_len);
- // Start turn tcp client now if needed
- if (cl->rtp_turn_context->transport != MS_TURN_CONTEXT_TRANSPORT_UDP) {
+ // TN patch - we always use TCP when TURN is enabled
+ {
if (!cl->rtp_turn_context->turn_tcp_client) {
cl->rtp_turn_context->turn_tcp_client = ms_turn_tcp_client_new(cl->rtp_turn_context,
cl->rtp_turn_context->transport == MS_TURN_CONTEXT_TRANSPORT_TLS,
@@ -1049,12 +1092,15 @@ static bool_t ice_check_list_gather_candidates(IceCheckList *cl, Session_Index *
if (!rtp_session_rtcp_mux_enabled(cl->rtp_session) && rtptp) {
struct sockaddr *sa = (struct sockaddr *)&cl->rtp_session->rtcp.gs.loc_addr;
if (cl->session->turn_enabled) {
+ // TN patch - clear TURN state due to stale nonce and sockets
+ clear_turn_state(rtptp, cl->rtcp_turn_context);
+
/* Define the RTP endpoint that will perform STUN encapsulation/decapsulation for TURN data */
meta_rtp_transport_set_endpoint(rtptp, ms_turn_context_create_endpoint(cl->rtcp_turn_context));
ms_turn_context_set_server_addr(cl->rtcp_turn_context, (struct sockaddr *)&cl->session->ss, cl->session->ss_len);
- // Start turn tcp client now if needed
- if (cl->rtcp_turn_context->transport != MS_TURN_CONTEXT_TRANSPORT_UDP) {
+ // TN patch - we always use TCP when TURN is enabled
+ {
if (!cl->rtcp_turn_context->turn_tcp_client) {
cl->rtcp_turn_context->turn_tcp_client = ms_turn_tcp_client_new(cl->rtcp_turn_context,
cl->rtcp_turn_context->transport == MS_TURN_CONTEXT_TRANSPORT_TLS,