Skip to content

Commit f8b7751

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 af0617e commit f8b7751

File tree

1 file changed

+64
-71
lines changed

1 file changed

+64
-71
lines changed

libavformat/whip.c

Lines changed: 64 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -389,19 +389,6 @@ static av_cold int certificate_key_init(AVFormatContext *s)
389389
return ret;
390390
}
391391

392-
static av_cold int dtls_initialize(AVFormatContext *s)
393-
{
394-
WHIPContext *whip = s->priv_data;
395-
/* reuse the udp created by whip */
396-
ff_tls_set_external_socket(whip->dtls_uc, whip->udp);
397-
398-
/* Make the socket non-blocking */
399-
ff_socket_nonblock(ffurl_get_file_handle(whip->dtls_uc), 1);
400-
whip->dtls_uc->flags |= AVIO_FLAG_NONBLOCK;
401-
402-
return 0;
403-
}
404-
405392
/**
406393
* Initialize and check the options for the WebRTC muxer.
407394
*/
@@ -1286,14 +1273,12 @@ static int udp_connect(AVFormatContext *s)
12861273
return ret;
12871274
}
12881275

1289-
static int ice_dtls_handshake(AVFormatContext *s)
1276+
static int handle_ice_handshake(AVFormatContext *s)
12901277
{
12911278
int ret = 0, size, i;
12921279
int64_t starttime = av_gettime(), now;
12931280
WHIPContext *whip = s->priv_data;
12941281
int is_dtls_active = whip->flags & WHIP_FLAG_DTLS_ACTIVE;
1295-
AVDictionary *opts = NULL;
1296-
char buf[256], *cert_buf = NULL, *key_buf = NULL;
12971282

12981283
if (whip->state < WHIP_STATE_UDP_CONNECTED || !whip->udp) {
12991284
av_log(whip, AV_LOG_ERROR, "UDP not connected, state=%d, udp=%p\n", whip->state, whip->udp);
@@ -1315,25 +1300,20 @@ static int ice_dtls_handshake(AVFormatContext *s)
13151300
goto end;
13161301
}
13171302

1318-
if (whip->state < WHIP_STATE_ICE_CONNECTING)
1319-
whip->state = WHIP_STATE_ICE_CONNECTING;
1303+
whip->state = WHIP_STATE_ICE_CONNECTING;
13201304
}
13211305

13221306
next_packet:
1323-
if (whip->state >= WHIP_STATE_DTLS_FINISHED)
1324-
/* DTLS handshake is done, exit the loop. */
1325-
break;
1326-
13271307
now = av_gettime();
13281308
if (now - starttime >= whip->handshake_timeout * 1000) {
1329-
av_log(whip, AV_LOG_ERROR, "DTLS handshake timeout=%dms, cost=%dms, elapsed=%dms, state=%d\n",
1309+
av_log(whip, AV_LOG_ERROR, "ICE handshake timeout=%dms, cost=%dms, elapsed=%dms, state=%d\n",
13301310
whip->handshake_timeout, ELAPSED(starttime, now), ELAPSED(whip->whip_starttime, now), whip->state);
13311311
ret = AVERROR(ETIMEDOUT);
13321312
goto end;
13331313
}
13341314

1335-
/* Read the STUN or DTLS messages from peer. */
1336-
for (i = 0; i < ICE_DTLS_READ_INTERVAL / 5 && whip->state < WHIP_STATE_ICE_CONNECTED; i++) {
1315+
/* Read the STUN or DTLS client hello from peer. */
1316+
for (i = 0; i < ICE_DTLS_READ_INTERVAL / 5; i++) {
13371317
ret = ffurl_read(whip->udp, whip->buf, sizeof(whip->buf));
13381318
if (ret > 0)
13391319
break;
@@ -1349,34 +1329,9 @@ static int ice_dtls_handshake(AVFormatContext *s)
13491329

13501330
/* Handle the ICE binding response. */
13511331
if (ice_is_binding_response(whip->buf, ret)) {
1352-
if (whip->state < WHIP_STATE_ICE_CONNECTED) {
1353-
if (whip->is_peer_ice_lite)
1354-
whip->state = WHIP_STATE_ICE_CONNECTED;
1332+
if (whip->is_peer_ice_lite) {
1333+
whip->state = WHIP_STATE_ICE_CONNECTED;
13551334
whip->whip_ice_time = av_gettime();
1356-
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",
1357-
whip->state, whip->ice_host, whip->ice_port, whip->whip_resource_url ? whip->whip_resource_url : "",
1358-
whip->ice_ufrag_remote, whip->ice_ufrag_local, ret, ELAPSED(whip->whip_starttime, av_gettime()));
1359-
1360-
ff_url_join(buf, sizeof(buf), "dtls", NULL, whip->ice_host, whip->ice_port, NULL);
1361-
av_dict_set_int(&opts, "mtu", whip->pkt_size, 0);
1362-
if (whip->cert_file) {
1363-
av_dict_set(&opts, "cert_file", whip->cert_file, 0);
1364-
} else
1365-
av_dict_set(&opts, "cert_pem", whip->cert_buf, 0);
1366-
1367-
if (whip->key_file) {
1368-
av_dict_set(&opts, "key_file", whip->key_file, 0);
1369-
} else
1370-
av_dict_set(&opts, "key_pem", whip->key_buf, 0);
1371-
av_dict_set_int(&opts, "external_sock", 1, 0);
1372-
av_dict_set_int(&opts, "listen", is_dtls_active ? 0 : 1, 0);
1373-
/* If got the first binding response, start DTLS handshake. */
1374-
ret = ffurl_open_whitelist(&whip->dtls_uc, buf, AVIO_FLAG_READ_WRITE, &s->interrupt_callback,
1375-
&opts, s->protocol_whitelist, s->protocol_blacklist, NULL);
1376-
av_dict_free(&opts);
1377-
if (ret < 0)
1378-
goto end;
1379-
dtls_initialize(s);
13801335
}
13811336
goto next_packet;
13821337
}
@@ -1388,29 +1343,64 @@ static int ice_dtls_handshake(AVFormatContext *s)
13881343
goto next_packet;
13891344
}
13901345

1391-
if ((is_dtls_packet(whip->buf, ret) || is_dtls_active) && whip->state >= WHIP_STATE_ICE_CONNECTED || whip->state == WHIP_STATE_ICE_CONNECTING) {
1392-
whip->state = WHIP_STATE_ICE_CONNECTED;
1393-
ret = ffurl_handshake(whip->dtls_uc);
1394-
if (ret < 0) {
1395-
whip->state = WHIP_STATE_FAILED;
1396-
av_log(whip, AV_LOG_VERBOSE, "DTLS session failed\n");
1397-
goto end;
1398-
}
1399-
if (!ret) {
1400-
whip->state = WHIP_STATE_DTLS_FINISHED;
1401-
whip->whip_dtls_time = av_gettime();
1402-
av_log(whip, AV_LOG_VERBOSE, "DTLS handshake is done, elapsed=%dms\n",
1403-
ELAPSED(whip->whip_starttime, whip->whip_dtls_time));
1346+
if (is_dtls_packet(whip->buf, ret) || whip->flags & WHIP_FLAG_DTLS_ACTIVE) {
1347+
if (whip->state < WHIP_STATE_ICE_CONNECTED) {
1348+
whip->state = WHIP_STATE_ICE_CONNECTED;
1349+
whip->whip_ice_time = av_gettime();
14041350
}
1405-
goto next_packet;
1351+
ret = 0;
1352+
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",
1353+
whip->state, whip->ice_host, whip->ice_port, whip->whip_resource_url ? whip->whip_resource_url : "",
1354+
whip->ice_ufrag_remote, whip->ice_ufrag_local, ret, ELAPSED(whip->whip_starttime, whip->whip_ice_time));
1355+
break;
14061356
}
14071357
}
1358+
end:
1359+
return ret;
1360+
}
14081361

1362+
static int handle_dtls_handshake(AVFormatContext *s)
1363+
{
1364+
int ret = 0;
1365+
WHIPContext *whip = s->priv_data;
1366+
AVDictionary *opts = NULL;
1367+
char buf[256];
1368+
1369+
ff_url_join(buf, sizeof(buf), "dtls", NULL, whip->ice_host, whip->ice_port, NULL);
1370+
av_dict_set_int(&opts, "mtu", whip->pkt_size, 0);
1371+
if (whip->cert_file) {
1372+
av_dict_set(&opts, "cert_file", whip->cert_file, 0);
1373+
} else
1374+
av_dict_set(&opts, "cert_pem", whip->cert_buf, 0);
1375+
1376+
if (whip->key_file) {
1377+
av_dict_set(&opts, "key_file", whip->key_file, 0);
1378+
} else
1379+
av_dict_set(&opts, "key_pem", whip->key_buf, 0);
1380+
av_dict_set_int(&opts, "external_sock", 1, 0);
1381+
av_dict_set_int(&opts, "listen", whip->flags & WHIP_FLAG_DTLS_ACTIVE ? 0 : 1, 0);
1382+
1383+
ret = ffurl_open_whitelist(&whip->dtls_uc, buf, AVIO_FLAG_READ_WRITE, &s->interrupt_callback,
1384+
&opts, s->protocol_whitelist, s->protocol_blacklist, NULL);
1385+
av_dict_free(&opts);
1386+
if (ret < 0)
1387+
goto end;
1388+
1389+
/* reuse the udp created by whip */
1390+
ff_tls_set_external_socket(whip->dtls_uc, whip->udp);
1391+
1392+
ret = ffurl_handshake(whip->dtls_uc);
1393+
if (ret < 0) {
1394+
whip->state = WHIP_STATE_FAILED;
1395+
av_log(whip, AV_LOG_VERBOSE, "DTLS session failed\n");
1396+
}
1397+
if (!ret) {
1398+
whip->state = WHIP_STATE_DTLS_FINISHED;
1399+
whip->whip_dtls_time = av_gettime();
1400+
av_log(whip, AV_LOG_VERBOSE, "DTLS handshake is done, elapsed=%dms\n",
1401+
ELAPSED(whip->whip_starttime, whip->whip_dtls_time));
1402+
}
14091403
end:
1410-
if (cert_buf)
1411-
av_free(cert_buf);
1412-
if (key_buf)
1413-
av_free(key_buf);
14141404
return ret;
14151405
}
14161406

@@ -1935,7 +1925,10 @@ static av_cold int whip_init(AVFormatContext *s)
19351925
if ((ret = udp_connect(s)) < 0)
19361926
goto end;
19371927

1938-
if ((ret = ice_dtls_handshake(s)) < 0)
1928+
if ((ret = handle_ice_handshake(s)) < 0)
1929+
goto end;
1930+
1931+
if ((ret = handle_dtls_handshake(s)) < 0)
19391932
goto end;
19401933

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

0 commit comments

Comments
 (0)