Unified · Split
| @@ -608,6 +608,10 @@ typedef struct TLSContext { · 607 unmodified lines | ||
| 608 | 608 | int dec_buf_size; |
| 609 | 609 | int dec_buf_offset; |
| 610 | 610 | |
| 611 | + char *send_buf; | |
| 612 | + int send_buf_size; | |
| 613 | + int send_buf_offset; | |
| 614 | + | |
| 611 | 615 | SecPkgContext_StreamSizes sizes; |
| 612 | 616 | |
| 613 | 617 | int connected; |
| @@ -692,6 +696,35 @@ static void init_sec_buffer_desc(SecBufferDesc *desc, SecBuffer *buffers, · 78 unmodified lines | ||
| 692 | 696 | desc->cBuffers = buffer_count; |
| 693 | 697 | } |
| 694 | 698 | |
| 699 | +static int tls_process_send_buffer(URLContext *h) | |
| 700 | +{ | |
| 701 | + TLSContext *c = h->priv_data; | |
| 702 | + TLSShared *s = &c->tls_shared; | |
| 703 | + URLContext *uc = s->is_dtls ? s->udp : s->tcp; | |
| 704 | + int ret; | |
| 705 | + | |
| 706 | + if (!c->send_buf) | |
| 707 | + return 0; | |
| 708 | + | |
| 709 | + ret = ffurl_write(uc, c->send_buf + c->send_buf_offset, c->send_buf_size - c->send_buf_offset); | |
| 710 | + if (ret == AVERROR(EAGAIN)) { | |
| 711 | + return AVERROR(EAGAIN); | |
| 712 | + } else if (ret < 0) { | |
| 713 | + av_log(h, AV_LOG_ERROR, "Writing encrypted data to socket failed\n"); | |
| 714 | + return AVERROR(EIO); | |
| 715 | + } | |
| 716 | + | |
| 717 | + c->send_buf_offset += ret; | |
| 718 | + | |
| 719 | + if (c->send_buf_offset < c->send_buf_size) | |
| 720 | + return AVERROR(EAGAIN); | |
| 721 | + | |
| 722 | + av_freep(&c->send_buf); | |
| 723 | + c->send_buf_size = c->send_buf_offset = 0; | |
| 724 | + | |
| 725 | + return 0; | |
| 726 | +} | |
| 727 | + | |
| 695 | 728 | static int tls_shutdown_client(URLContext *h) |
| 696 | 729 | { |
| 697 | 730 | TLSContext *c = h->priv_data; |
| @@ -710,6 +743,11 @@ static int tls_shutdown_client(URLContext *h) · 12 unmodified lines | ||
| 710 | 743 | init_sec_buffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut)); |
| 711 | 744 | init_sec_buffer_desc(&BuffDesc, &Buffer, 1); |
| 712 | 745 | |
| 746 | + uc->flags &= ~AVIO_FLAG_NONBLOCK; | |
| 747 | + ret = tls_process_send_buffer(h); | |
| 748 | + if (ret < 0) | |
| 749 | + return ret; | |
| 750 | + | |
| 713 | 751 | sspi_ret = ApplyControlToken(&c->ctxt_handle, &BuffDesc); |
| 714 | 752 | if (sspi_ret != SEC_E_OK) |
| 715 | 753 | av_log(h, AV_LOG_ERROR, "ApplyControlToken failed\n"); |
| @@ -729,7 +767,6 @@ static int tls_shutdown_client(URLContext *h) · 13 unmodified lines | ||
| 729 | 767 | |
| 730 | 768 | if (outbuf.pvBuffer) { |
| 731 | 769 | if (outbuf.cbBuffer > 0) { |
| 732 | − uc->flags &= ~AVIO_FLAG_NONBLOCK; | |
| 733 | 770 | ret = ffurl_write(uc, outbuf.pvBuffer, outbuf.cbBuffer); |
| 734 | 771 | if (ret < 0 || ret != outbuf.cbBuffer) |
| 735 | 772 | av_log(h, AV_LOG_ERROR, "Failed to send close message\n"); |
| @@ -761,6 +798,9 @@ static int tls_close(URLContext *h) · 25 unmodified lines | ||
| 761 | 798 | av_freep(&c->dec_buf); |
| 762 | 799 | c->dec_buf_size = c->dec_buf_offset = 0; |
| 763 | 800 | |
| 801 | + av_freep(&c->send_buf); | |
| 802 | + c->send_buf_size = c->send_buf_offset = 0; | |
| 803 | + | |
| 764 | 804 | if (s->is_dtls) { |
| 765 | 805 | if (!s->external_sock) |
| 766 | 806 | ffurl_closep(&c->tls_shared.udp); |
| @@ -1264,6 +1304,11 @@ static int tls_read(URLContext *h, uint8_t *buf, int len) · 497 unmodified lines | ||
| 1264 | 1304 | goto cleanup; |
| 1265 | 1305 | } |
| 1266 | 1306 | sspi_ret = SEC_E_OK; |
| 1307 | + | |
| 1308 | + /* if somehow any send data was left, it is now invalid */ | |
| 1309 | + av_freep(&c->send_buf); | |
| 1310 | + c->send_buf_size = c->send_buf_offset = 0; | |
| 1311 | + | |
| 1267 | 1312 | continue; |
| 1268 | 1313 | } else if (sspi_ret == SEC_I_CONTEXT_EXPIRED) { |
| 1269 | 1314 | c->sspi_close_notify = 1; |
| @@ -1308,10 +1353,16 @@ static int tls_write(URLContext *h, const uint8_t *buf, int len) · 38 unmodified lines | ||
| 1308 | 1353 | TLSShared *s = &c->tls_shared; |
| 1309 | 1354 | URLContext *uc = s->is_dtls ? s->udp : s->tcp; |
| 1310 | 1355 | SECURITY_STATUS sspi_ret; |
| 1311 | − int ret = 0, data_size; | |
| 1312 | − uint8_t *data = NULL; | |
| 1313 | 1356 | SecBuffer outbuf[4]; |
| 1314 | 1357 | SecBufferDesc outbuf_desc; |
| 1358 | + int ret = 0; | |
| 1359 | + | |
| 1360 | + uc->flags &= ~AVIO_FLAG_NONBLOCK; | |
| 1361 | + uc->flags |= h->flags & AVIO_FLAG_NONBLOCK; | |
| 1362 | + | |
| 1363 | + ret = tls_process_send_buffer(h); | |
| 1364 | + if (ret < 0) | |
| 1365 | + return ret; | |
| 1315 | 1366 | |
| 1316 | 1367 | if (c->sizes.cbMaximumMessage == 0) { |
| 1317 | 1368 | sspi_ret = QueryContextAttributes(&c->ctxt_handle, SECPKG_ATTR_STREAM_SIZES, &c->sizes); |
| @@ -1322,50 +1373,46 @@ static int tls_write(URLContext *h, const uint8_t *buf, int len) · 4 unmodified lines | ||
| 1322 | 1373 | /* limit how much data we can consume */ |
| 1323 | 1374 | len = FFMIN(len, c->sizes.cbMaximumMessage - c->sizes.cbHeader - c->sizes.cbTrailer); |
| 1324 | 1375 | |
| 1325 | − data_size = c->sizes.cbHeader + len + c->sizes.cbTrailer; | |
| 1326 | − data = av_malloc(data_size); | |
| 1327 | − if (data == NULL) | |
| 1376 | + c->send_buf_size = c->sizes.cbHeader + len + c->sizes.cbTrailer; | |
| 1377 | + c->send_buf = av_malloc(c->send_buf_size); | |
| 1378 | + if (c->send_buf == NULL) | |
| 1328 | 1379 | return AVERROR(ENOMEM); |
| 1329 | 1380 | |
| 1330 | 1381 | init_sec_buffer(&outbuf[0], SECBUFFER_STREAM_HEADER, |
| 1331 | − data, c->sizes.cbHeader); | |
| 1382 | + c->send_buf, c->sizes.cbHeader); | |
| 1332 | 1383 | init_sec_buffer(&outbuf[1], SECBUFFER_DATA, |
| 1333 | − data + c->sizes.cbHeader, len); | |
| 1384 | + c->send_buf + c->sizes.cbHeader, len); | |
| 1334 | 1385 | init_sec_buffer(&outbuf[2], SECBUFFER_STREAM_TRAILER, |
| 1335 | − data + c->sizes.cbHeader + len, | |
| 1336 | − c->sizes.cbTrailer); | |
| 1386 | + c->send_buf + c->sizes.cbHeader + len, | |
| 1387 | + c->sizes.cbTrailer); | |
| 1337 | 1388 | init_sec_buffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0); |
| 1338 | 1389 | init_sec_buffer_desc(&outbuf_desc, outbuf, 4); |
| 1339 | 1390 | |
| 1340 | 1391 | memcpy(outbuf[1].pvBuffer, buf, len); |
| 1341 | 1392 | |
| 1342 | 1393 | sspi_ret = EncryptMessage(&c->ctxt_handle, 0, &outbuf_desc, 0); |
| 1343 | − if (sspi_ret == SEC_E_OK) { | |
| 1344 | − len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer; | |
| 1345 | − | |
| 1346 | − uc->flags &= ~AVIO_FLAG_NONBLOCK; | |
| 1347 | − uc->flags |= h->flags & AVIO_FLAG_NONBLOCK; | |
| 1348 | − | |
| 1349 | − ret = ffurl_write(uc, data, len); | |
| 1350 | − if (ret == AVERROR(EAGAIN)) { | |
| 1351 | − goto done; | |
| 1352 | − } else if (ret < 0 || ret != len) { | |
| 1353 | − ret = AVERROR(EIO); | |
| 1354 | − av_log(h, AV_LOG_ERROR, "Writing encrypted data to socket failed\n"); | |
| 1355 | − goto done; | |
| 1356 | − } | |
| 1357 | − } else { | |
| 1394 | + if (sspi_ret != SEC_E_OK) { | |
| 1395 | + av_freep(&c->send_buf); | |
| 1358 | 1396 | av_log(h, AV_LOG_ERROR, "Encrypting data failed\n"); |
| 1359 | 1397 | if (sspi_ret == SEC_E_INSUFFICIENT_MEMORY) |
| 1360 | − ret = AVERROR(ENOMEM); | |
| 1361 | − else | |
| 1362 | − ret = AVERROR(EIO); | |
| 1363 | − goto done; | |
| 1398 | + return AVERROR(ENOMEM); | |
| 1399 | + return AVERROR(EIO); | |
| 1400 | + } | |
| 1401 | + | |
| 1402 | + c->send_buf_size = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer; | |
| 1403 | + c->send_buf_offset = 0; | |
| 1404 | + | |
| 1405 | + ret = tls_process_send_buffer(h); | |
| 1406 | + if (ret == AVERROR(EAGAIN)) { | |
| 1407 | + /* We always need to signal that we consumed all (encryped) data since schannel must not | |
| 1408 | + be fed the same data again. Sending will then be completed next call to this function, | |
| 1409 | + and EAGAIN returned until all remaining buffer is sent. */ | |
| 1410 | + return outbuf[1].cbBuffer; | |
| 1411 | + } else if (ret < 0) { | |
| 1412 | + return ret; | |
| 1364 | 1413 | } |
| 1365 | 1414 | |
| 1366 | −done: | |
| 1367 | − av_freep(&data); | |
| 1368 | − return ret < 0 ? ret : outbuf[1].cbBuffer; | |
| 1415 | + return outbuf[1].cbBuffer; | |
| 1369 | 1416 | } |
| 1370 | 1417 | |
| 1371 | 1418 | static int tls_get_file_handle(URLContext *h) |