Improve hls VOD mode hls performance problem.
[ffmpeg.git] / libavformat / tls_securetransport.c
index 9951b90..3738054 100644 (file)
@@ -22,6 +22,7 @@
 
 
 #include "avformat.h"
+#include "avio_internal.h"
 #include "internal.h"
 #include "network.h"
 #include "os_support.h"
@@ -53,7 +54,7 @@ static int print_tls_error(URLContext *h, int ret)
     TLSContext *c = h->priv_data;
     switch (ret) {
     case errSSLWouldBlock:
-        break;
+        return AVERROR(EAGAIN);
     case errSSLXCertChainInvalid:
         av_log(h, AV_LOG_ERROR, "Invalid certificate chain\n");
         return AVERROR(EIO);
@@ -68,6 +69,9 @@ static int print_tls_error(URLContext *h, int ret)
 
 static int import_pem(URLContext *h, char *path, CFArrayRef *array)
 {
+#if !HAVE_SECITEMIMPORT
+    return AVERROR_PATCHWELCOME;
+#else
     AVIOContext *s = NULL;
     CFDataRef data = NULL;
     int64_t ret = 0;
@@ -80,8 +84,9 @@ static int import_pem(URLContext *h, char *path, CFArrayRef *array)
         goto end;
     }
 
-    if ((ret = avio_open2(&s, path, AVIO_FLAG_READ,
-                          &h->interrupt_callback, NULL)) < 0)
+    if ((ret = ffio_open_whitelist(&s, path, AVIO_FLAG_READ,
+                                   &h->interrupt_callback, NULL,
+                                   h->protocol_whitelist, h->protocol_blacklist)) < 0)
         goto end;
 
     if ((ret = avio_size(s)) < 0)
@@ -122,6 +127,7 @@ end:
     if (s)
         avio_close(s);
     return ret;
+#endif
 }
 
 static int load_ca(URLContext *h)
@@ -191,7 +197,8 @@ static OSStatus tls_read_cb(SSLConnectionRef connection, void *data, size_t *dat
 {
     URLContext *h = (URLContext*)connection;
     TLSContext *c = h->priv_data;
-    int read = ffurl_read_complete(c->tls_shared.tcp, data, *dataLength);
+    size_t requested = *dataLength;
+    int read = ffurl_read(c->tls_shared.tcp, data, requested);
     if (read <= 0) {
         *dataLength = 0;
         switch(AVUNERROR(read)) {
@@ -208,7 +215,10 @@ static OSStatus tls_read_cb(SSLConnectionRef connection, void *data, size_t *dat
         }
     } else {
         *dataLength = read;
-        return noErr;
+        if (read < requested)
+            return errSSLWouldBlock;
+        else
+            return noErr;
     }
 }
 
@@ -273,13 +283,13 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op
     if (s->ca_file) {
         if ((ret = load_ca(h)) < 0)
             goto fail;
-        CHECK_ERROR(SSLSetSessionOption, c->ssl_context, kSSLSessionOptionBreakOnServerAuth, true);
     }
+    if (s->ca_file || !s->verify)
+        CHECK_ERROR(SSLSetSessionOption, c->ssl_context, kSSLSessionOptionBreakOnServerAuth, true);
     if (s->cert_file)
         if ((ret = load_cert(h)) < 0)
             goto fail;
-    if (s->verify)
-        CHECK_ERROR(SSLSetPeerDomainName, c->ssl_context, s->host, strlen(s->host));
+    CHECK_ERROR(SSLSetPeerDomainName, c->ssl_context, s->host, strlen(s->host));
     CHECK_ERROR(SSLSetIOFuncs, c->ssl_context, tls_read_cb, tls_write_cb);
     CHECK_ERROR(SSLSetConnection, c->ssl_context, h);
     while (1) {
@@ -320,12 +330,13 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op
             if (peerTrust)
                 CFRelease(peerTrust);
         }
-        if (status == noErr)
+        if (status == noErr) {
             break;
-
-        av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session: %i\n", (int)status);
-        ret = AVERROR(EIO);
-        goto fail;
+        } else if (status != errSSLWouldBlock) {
+            av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session: %i\n", (int)status);
+            ret = AVERROR(EIO);
+            goto fail;
+        }
     }
 
     return 0;
@@ -342,6 +353,9 @@ static int map_ssl_error(OSStatus status, size_t processed)
     case errSSLClosedGraceful:
     case errSSLClosedNoNotify:
         return 0;
+    case errSSLWouldBlock:
+        if (processed > 0)
+            return processed;
     default:
         return (int)status;
     }
@@ -350,8 +364,13 @@ static int map_ssl_error(OSStatus status, size_t processed)
 static int tls_read(URLContext *h, uint8_t *buf, int size)
 {
     TLSContext *c = h->priv_data;
-    size_t processed;
-    int ret = map_ssl_error(SSLRead(c->ssl_context, buf, size, &processed), processed);
+    size_t available = 0, processed = 0;
+    int ret;
+    SSLGetBufferedReadSize(c->ssl_context, &available);
+    if (available)
+        size = FFMIN(available, size);
+    ret = SSLRead(c->ssl_context, buf, size, &processed);
+    ret = map_ssl_error(ret, processed);
     if (ret > 0)
         return ret;
     if (ret == 0)
@@ -362,8 +381,9 @@ static int tls_read(URLContext *h, uint8_t *buf, int size)
 static int tls_write(URLContext *h, const uint8_t *buf, int size)
 {
     TLSContext *c = h->priv_data;
-    size_t processed;
-    int ret = map_ssl_error(SSLWrite(c->ssl_context, buf, size, &processed), processed);
+    size_t processed = 0;
+    int ret = SSLWrite(c->ssl_context, buf, size, &processed);
+    ret = map_ssl_error(ret, processed);
     if (ret > 0)
         return ret;
     if (ret == 0)
@@ -371,6 +391,12 @@ static int tls_write(URLContext *h, const uint8_t *buf, int size)
     return print_tls_error(h, ret);
 }
 
+static int tls_get_file_handle(URLContext *h)
+{
+    TLSContext *c = h->priv_data;
+    return ffurl_get_file_handle(c->tls_shared.tcp);
+}
+
 static const AVOption options[] = {
     TLS_COMMON_OPTIONS(TLSContext, tls_shared),
     { NULL }
@@ -383,12 +409,13 @@ static const AVClass tls_class = {
     .version    = LIBAVUTIL_VERSION_INT,
 };
 
-URLProtocol ff_tls_securetransport_protocol = {
+const URLProtocol ff_tls_protocol = {
     .name           = "tls",
     .url_open2      = tls_open,
     .url_read       = tls_read,
     .url_write      = tls_write,
     .url_close      = tls_close,
+    .url_get_file_handle = tls_get_file_handle,
     .priv_data_size = sizeof(TLSContext),
     .flags          = URL_PROTOCOL_FLAG_NETWORK,
     .priv_data_class = &tls_class,