Skip to content

Commit 5982042

Browse files
committed
avformat/whip: simplify and modularize the ICE and DTLS
We try to perform dtls handshake when the ICE is totally done. Refer to RFC8445, When peer's ICE is lite, the peer won't trigged check so FFmpeg just send STUN request and receive response, then ICE is done. When peer's ICE is full, the peer will send STUN request after reponse FFmpeg's request to ensure candidate pair become valid in both directions. Then the peer does nomination, and ICE is done. Signed-off-by: Jack Lau <[email protected]>
1 parent fcf99aa commit 5982042

File tree

1 file changed

+62
-73
lines changed

1 file changed

+62
-73
lines changed

libavformat/whip.c

Lines changed: 62 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -373,19 +373,6 @@ static av_cold int certificate_key_init(AVFormatContext *s)
373373
return ret;
374374
}
375375

376-
static av_cold int dtls_initialize(AVFormatContext *s)
377-
{
378-
WHIPContext *whip = s->priv_data;
379-
/* reuse the udp created by whip */
380-
ff_tls_set_external_socket(whip->dtls_uc, whip->udp);
381-
382-
/* Make the socket non-blocking */
383-
ff_socket_nonblock(ffurl_get_file_handle(whip->dtls_uc), 1);
384-
whip->dtls_uc->flags |= AVIO_FLAG_NONBLOCK;
385-
386-
return 0;
387-
}
388-
389376
/**
390377
* Initialize and check the options for the WebRTC muxer.
391378
*/
@@ -1232,14 +1219,12 @@ static int udp_connect(AVFormatContext *s)
12321219
return ret;
12331220
}
12341221

1235-
static int ice_dtls_handshake(AVFormatContext *s)
1222+
static int ice_handshake(AVFormatContext *s)
12361223
{
12371224
int ret = 0, size, i;
12381225
int64_t starttime = av_gettime(), now;
12391226
WHIPContext *whip = s->priv_data;
12401227
int is_dtls_active = whip->flags & WHIP_FLAG_DTLS_ACTIVE;
1241-
AVDictionary *opts = NULL;
1242-
char buf[256], *cert_buf = NULL, *key_buf = NULL;
12431228

12441229
if (whip->state < WHIP_STATE_UDP_CONNECTED || !whip->udp) {
12451230
av_log(whip, AV_LOG_ERROR, "UDP not connected, state=%d, udp=%p\n", whip->state, whip->udp);
@@ -1261,25 +1246,20 @@ static int ice_dtls_handshake(AVFormatContext *s)
12611246
goto end;
12621247
}
12631248

1264-
if (whip->state < WHIP_STATE_ICE_CONNECTING)
1265-
whip->state = WHIP_STATE_ICE_CONNECTING;
1249+
whip->state = WHIP_STATE_ICE_CONNECTING;
12661250
}
12671251

12681252
next_packet:
1269-
if (whip->state >= WHIP_STATE_DTLS_FINISHED)
1270-
/* DTLS handshake is done, exit the loop. */
1271-
break;
1272-
12731253
now = av_gettime();
12741254
if (now - starttime >= whip->handshake_timeout * 1000) {
1275-
av_log(whip, AV_LOG_ERROR, "DTLS handshake timeout=%dms, cost=%dms, elapsed=%dms, state=%d\n",
1255+
av_log(whip, AV_LOG_ERROR, "ICE handshake timeout=%dms, cost=%dms, elapsed=%dms, state=%d\n",
12761256
whip->handshake_timeout, ELAPSED(starttime, now), ELAPSED(whip->whip_starttime, now), whip->state);
12771257
ret = AVERROR(ETIMEDOUT);
12781258
goto end;
12791259
}
12801260

1281-
/* Read the STUN or DTLS messages from peer. */
1282-
for (i = 0; i < ICE_DTLS_READ_INTERVAL / 5 && whip->state < WHIP_STATE_ICE_CONNECTED; i++) {
1261+
/* Read the STUN or DTLS client hello from peer. */
1262+
for (i = 0; i < ICE_DTLS_READ_INTERVAL / 5; i++) {
12831263
ret = ffurl_read(whip->udp, whip->buf, sizeof(whip->buf));
12841264
if (ret > 0)
12851265
break;
@@ -1295,35 +1275,8 @@ static int ice_dtls_handshake(AVFormatContext *s)
12951275

12961276
/* Handle the ICE binding response. */
12971277
if (ice_is_binding_response(whip->buf, ret)) {
1298-
if (whip->state < WHIP_STATE_ICE_CONNECTED) {
1299-
if (whip->is_peer_ice_lite)
1300-
whip->state = WHIP_STATE_ICE_CONNECTED;
1301-
whip->whip_ice_time = av_gettime();
1302-
av_log(whip, AV_LOG_VERBOSE, "ICE STUN ok, state=%d, url=udp://%s:%d, location=%s, username=%s:%s, res=%dB, elapsed=%dms\n",
1303-
whip->state, whip->ice_host, whip->ice_port, whip->whip_resource_url ? whip->whip_resource_url : "",
1304-
whip->ice_ufrag_remote, whip->ice_ufrag_local, ret, ELAPSED(whip->whip_starttime, av_gettime()));
1305-
1306-
ff_url_join(buf, sizeof(buf), "dtls", NULL, whip->ice_host, whip->ice_port, NULL);
1307-
av_dict_set_int(&opts, "mtu", whip->pkt_size, 0);
1308-
if (whip->cert_file) {
1309-
av_dict_set(&opts, "cert_file", whip->cert_file, 0);
1310-
} else
1311-
av_dict_set(&opts, "cert_pem", whip->cert_buf, 0);
1312-
1313-
if (whip->key_file) {
1314-
av_dict_set(&opts, "key_file", whip->key_file, 0);
1315-
} else
1316-
av_dict_set(&opts, "key_pem", whip->key_buf, 0);
1317-
av_dict_set_int(&opts, "external_sock", 1, 0);
1318-
av_dict_set_int(&opts, "listen", is_dtls_active ? 0 : 1, 0);
1319-
/* If got the first binding response, start DTLS handshake. */
1320-
ret = ffurl_open_whitelist(&whip->dtls_uc, buf, AVIO_FLAG_READ_WRITE, &s->interrupt_callback,
1321-
&opts, s->protocol_whitelist, s->protocol_blacklist, NULL);
1322-
av_dict_free(&opts);
1323-
if (ret < 0)
1324-
goto end;
1325-
dtls_initialize(s);
1326-
}
1278+
if (whip->is_peer_ice_lite)
1279+
whip->state = WHIP_STATE_ICE_CONNECTED;
13271280
goto next_packet;
13281281
}
13291282

@@ -1334,29 +1287,62 @@ static int ice_dtls_handshake(AVFormatContext *s)
13341287
goto next_packet;
13351288
}
13361289

1337-
if ((is_dtls_packet(whip->buf, ret) || is_dtls_active) && whip->state >= WHIP_STATE_ICE_CONNECTED || whip->state == WHIP_STATE_ICE_CONNECTING) {
1290+
if (is_dtls_packet(whip->buf, ret) || whip->flags & WHIP_FLAG_DTLS_ACTIVE) {
13381291
whip->state = WHIP_STATE_ICE_CONNECTED;
1339-
ret = ffurl_handshake(whip->dtls_uc);
1340-
if (ret < 0) {
1341-
whip->state = WHIP_STATE_FAILED;
1342-
av_log(whip, AV_LOG_VERBOSE, "DTLS session failed\n");
1343-
goto end;
1344-
}
1345-
if (!ret) {
1346-
whip->state = WHIP_STATE_DTLS_FINISHED;
1347-
whip->whip_dtls_time = av_gettime();
1348-
av_log(whip, AV_LOG_VERBOSE, "DTLS handshake is done, elapsed=%dms\n",
1349-
ELAPSED(whip->whip_starttime, whip->whip_dtls_time));
1350-
}
1351-
goto next_packet;
1292+
ret = 0;
1293+
whip->whip_ice_time = av_gettime();
1294+
av_log(whip, AV_LOG_VERBOSE, "ICE STUN ok, state=%d, url=udp://%s:%d, location=%s, username=%s:%s, res=%dB, elapsed=%dms\n",
1295+
whip->state, whip->ice_host, whip->ice_port, whip->whip_resource_url ? whip->whip_resource_url : "",
1296+
whip->ice_ufrag_remote, whip->ice_ufrag_local, ret, ELAPSED(whip->whip_starttime, av_gettime()));
1297+
break;
13521298
}
13531299
}
1300+
end:
1301+
return ret;
1302+
}
13541303

1304+
static int dtls_handshake(AVFormatContext *s)
1305+
{
1306+
int ret = 0;
1307+
WHIPContext *whip = s->priv_data;
1308+
AVDictionary *opts = NULL;
1309+
char buf[256];
1310+
1311+
ff_url_join(buf, sizeof(buf), "dtls", NULL, whip->ice_host, whip->ice_port, NULL);
1312+
av_dict_set_int(&opts, "mtu", whip->pkt_size, 0);
1313+
if (whip->cert_file) {
1314+
av_dict_set(&opts, "cert_file", whip->cert_file, 0);
1315+
} else
1316+
av_dict_set(&opts, "cert_pem", whip->cert_buf, 0);
1317+
1318+
if (whip->key_file) {
1319+
av_dict_set(&opts, "key_file", whip->key_file, 0);
1320+
} else
1321+
av_dict_set(&opts, "key_pem", whip->key_buf, 0);
1322+
av_dict_set_int(&opts, "external_sock", 1, 0);
1323+
av_dict_set_int(&opts, "listen", whip->flags & WHIP_FLAG_DTLS_ACTIVE ? 0 : 1, 0);
1324+
/* If got the first binding response, start DTLS handshake. */
1325+
ret = ffurl_open_whitelist(&whip->dtls_uc, buf, AVIO_FLAG_READ_WRITE, &s->interrupt_callback,
1326+
&opts, s->protocol_whitelist, s->protocol_blacklist, NULL);
1327+
av_dict_free(&opts);
1328+
if (ret < 0)
1329+
goto end;
1330+
1331+
/* reuse the udp created by whip */
1332+
ff_tls_set_external_socket(whip->dtls_uc, whip->udp);
1333+
1334+
ret = ffurl_handshake(whip->dtls_uc);
1335+
if (ret < 0) {
1336+
whip->state = WHIP_STATE_FAILED;
1337+
av_log(whip, AV_LOG_VERBOSE, "DTLS session failed\n");
1338+
}
1339+
if (!ret) {
1340+
whip->state = WHIP_STATE_DTLS_FINISHED;
1341+
whip->whip_dtls_time = av_gettime();
1342+
av_log(whip, AV_LOG_VERBOSE, "DTLS handshake is done, elapsed=%dms\n",
1343+
ELAPSED(whip->whip_starttime, whip->whip_dtls_time));
1344+
}
13551345
end:
1356-
if (cert_buf)
1357-
av_free(cert_buf);
1358-
if (key_buf)
1359-
av_free(key_buf);
13601346
return ret;
13611347
}
13621348

@@ -1866,7 +1852,10 @@ static av_cold int whip_init(AVFormatContext *s)
18661852
if ((ret = udp_connect(s)) < 0)
18671853
goto end;
18681854

1869-
if ((ret = ice_dtls_handshake(s)) < 0)
1855+
if ((ret = ice_handshake(s)) < 0)
1856+
goto end;
1857+
1858+
if ((ret = dtls_handshake(s)) < 0)
18701859
goto end;
18711860

18721861
if ((ret = setup_srtp(s)) < 0)

0 commit comments

Comments
 (0)