diff --git a/libavformat/tls.c b/libavformat/tls.c index d5de5ee8000854172069e76739883769065316d9..42a1e303a6f2a9bdace354c2e1507ebd99bc9608 100644 --- a/libavformat/tls.c +++ b/libavformat/tls.c @@ -36,6 +36,33 @@ if (c->cred) \ gnutls_certificate_free_credentials(c->cred); \ } while (0) + +static ssize_t gnutls_url_pull(gnutls_transport_ptr_t transport, + void *buf, size_t len) +{ + URLContext *h = (URLContext*) transport; + int ret = ffurl_read(h, buf, len); + if (ret >= 0) + return ret; + if (ret == AVERROR(EAGAIN)) + errno = EAGAIN; + else + errno = EIO; + return -1; +} +static ssize_t gnutls_url_push(gnutls_transport_ptr_t transport, + const void *buf, size_t len) +{ + URLContext *h = (URLContext*) transport; + int ret = ffurl_write(h, buf, len); + if (ret >= 0) + return ret; + if (ret == AVERROR(EAGAIN)) + errno = EAGAIN; + else + errno = EIO; + return -1; +} #elif CONFIG_OPENSSL #include <openssl/bio.h> #include <openssl/ssl.h> @@ -49,6 +76,70 @@ if (c->ctx) \ SSL_CTX_free(c->ctx); \ } while (0) + +static int url_bio_create(BIO *b) +{ + b->init = 1; + b->ptr = NULL; + b->flags = 0; + return 1; +} + +static int url_bio_destroy(BIO *b) +{ + return 1; +} + +static int url_bio_bread(BIO *b, char *buf, int len) +{ + URLContext *h = b->ptr; + int ret = ffurl_read(h, buf, len); + if (ret >= 0) + return ret; + BIO_clear_retry_flags(b); + if (ret == AVERROR(EAGAIN)) + BIO_set_retry_read(b); + return -1; +} + +static int url_bio_bwrite(BIO *b, const char *buf, int len) +{ + URLContext *h = b->ptr; + int ret = ffurl_write(h, buf, len); + if (ret >= 0) + return ret; + BIO_clear_retry_flags(b); + if (ret == AVERROR(EAGAIN)) + BIO_set_retry_write(b); + return -1; +} + +static long url_bio_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + if (cmd == BIO_CTRL_FLUSH) { + BIO_clear_retry_flags(b); + return 1; + } + return 0; +} + +static int url_bio_bputs(BIO *b, const char *str) +{ + return url_bio_bwrite(b, str, strlen(str)); +} + +static BIO_METHOD url_bio_method = { + .type = BIO_TYPE_SOURCE_SINK, + .name = "urlprotocol bio", + .bwrite = url_bio_bwrite, + .bread = url_bio_bread, + .bputs = url_bio_bputs, + .bgets = NULL, + .ctrl = url_bio_ctrl, + .create = url_bio_create, + .destroy = url_bio_destroy, +}; + #endif #include "network.h" #include "os_support.h" @@ -148,6 +239,9 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op struct addrinfo hints = { 0 }, *ai = NULL; const char *proxy_path; int use_proxy; +#if CONFIG_OPENSSL + BIO *bio; +#endif ff_tls_init(); @@ -220,8 +314,10 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op } } gnutls_credentials_set(c->session, GNUTLS_CRD_CERTIFICATE, c->cred); - gnutls_transport_set_ptr(c->session, (gnutls_transport_ptr_t) - (intptr_t) c->fd); + c->tcp->flags |= AVIO_FLAG_NONBLOCK; + gnutls_transport_set_pull_function(c->session, gnutls_url_pull); + gnutls_transport_set_push_function(c->session, gnutls_url_push); + gnutls_transport_set_ptr(c->session, c->tcp); gnutls_priority_set_direct(c->session, "NORMAL", NULL); while (1) { ret = gnutls_handshake(c->session); @@ -293,7 +389,10 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op ret = AVERROR(EIO); goto fail; } - SSL_set_fd(c->ssl, c->fd); + bio = BIO_new(&url_bio_method); + c->tcp->flags |= AVIO_FLAG_NONBLOCK; + bio->ptr = c->tcp; + SSL_set_bio(c->ssl, bio, bio); if (!c->listen && !numerichost) SSL_set_tlsext_host_name(c->ssl, host); while (1) {