Some callers assume that item_name is always set, so this may be considered an API break. This reverts commit 0c6203c97a99f69dbaa6e4011d48c331e1111f5e.
		
			
				
	
	
		
			218 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			218 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * TLS/SSL Protocol
 | 
						|
 * Copyright (c) 2011 Martin Storsjo
 | 
						|
 * Copyright (c) 2017 sfan5 <sfan5@live.de>
 | 
						|
 *
 | 
						|
 * This file is part of FFmpeg.
 | 
						|
 *
 | 
						|
 * FFmpeg is free software; you can redistribute it and/or
 | 
						|
 * modify it under the terms of the GNU Lesser General Public
 | 
						|
 * License as published by the Free Software Foundation; either
 | 
						|
 * version 2.1 of the License, or (at your option) any later version.
 | 
						|
 *
 | 
						|
 * FFmpeg is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
 * Lesser General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU Lesser General Public
 | 
						|
 * License along with FFmpeg; if not, write to the Free Software
 | 
						|
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
						|
 */
 | 
						|
 | 
						|
#include "avformat.h"
 | 
						|
#include "internal.h"
 | 
						|
#include "network.h"
 | 
						|
#include "url.h"
 | 
						|
#include "tls.h"
 | 
						|
#include "libavcodec/internal.h"
 | 
						|
#include "libavutil/avutil.h"
 | 
						|
#include "libavutil/opt.h"
 | 
						|
 | 
						|
#include <tls.h>
 | 
						|
 | 
						|
typedef struct TLSContext {
 | 
						|
    const AVClass *class;
 | 
						|
    TLSShared tls_shared;
 | 
						|
    struct tls *ctx;
 | 
						|
} TLSContext;
 | 
						|
 | 
						|
static int ff_tls_close(URLContext *h)
 | 
						|
{
 | 
						|
    TLSContext *p = h->priv_data;
 | 
						|
    if (p->ctx) {
 | 
						|
        tls_close(p->ctx);
 | 
						|
        tls_free(p->ctx);
 | 
						|
    }
 | 
						|
    ffurl_closep(&p->tls_shared.tcp);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static ssize_t tls_read_callback(struct tls *ctx, void *buf, size_t buflen, void *cb_arg)
 | 
						|
{
 | 
						|
    URLContext *h = (URLContext*) cb_arg;
 | 
						|
    int ret = ffurl_read(h, buf, buflen);
 | 
						|
    if (ret == AVERROR(EAGAIN))
 | 
						|
        return TLS_WANT_POLLIN;
 | 
						|
    else if (ret == AVERROR_EXIT)
 | 
						|
        return 0;
 | 
						|
    return ret >= 0 ? ret : -1;
 | 
						|
}
 | 
						|
 | 
						|
static ssize_t tls_write_callback(struct tls *ctx, const void *buf, size_t buflen, void *cb_arg)
 | 
						|
{
 | 
						|
    URLContext *h = (URLContext*) cb_arg;
 | 
						|
    int ret = ffurl_write(h, buf, buflen);
 | 
						|
    if (ret == AVERROR(EAGAIN))
 | 
						|
        return TLS_WANT_POLLOUT;
 | 
						|
    else if (ret == AVERROR_EXIT)
 | 
						|
        return 0;
 | 
						|
    return ret >= 0 ? ret : -1;
 | 
						|
}
 | 
						|
 | 
						|
static int ff_tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
 | 
						|
{
 | 
						|
    TLSContext *p = h->priv_data;
 | 
						|
    TLSShared *c = &p->tls_shared;
 | 
						|
    struct tls_config *cfg = NULL;
 | 
						|
    int ret;
 | 
						|
 | 
						|
    if (tls_init() == -1) {
 | 
						|
        ret = AVERROR(EIO);
 | 
						|
        goto fail;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((ret = ff_tls_open_underlying(c, h, uri, options)) < 0)
 | 
						|
        goto fail;
 | 
						|
 | 
						|
    p->ctx = !c->listen ? tls_client() : tls_server();
 | 
						|
    if (!p->ctx) {
 | 
						|
        ret = AVERROR(EIO);
 | 
						|
        goto fail;
 | 
						|
    }
 | 
						|
 | 
						|
    cfg = tls_config_new();
 | 
						|
    if (!p->ctx) {
 | 
						|
        ret = AVERROR(EIO);
 | 
						|
        goto fail;
 | 
						|
    }
 | 
						|
    if (tls_config_set_protocols(cfg, TLS_PROTOCOLS_ALL) == -1)
 | 
						|
        goto err_config;
 | 
						|
    // While TLSv1.0 and TLSv1.1 are already enabled by the above,
 | 
						|
    // we need to be less strict with ciphers so it works in practice.
 | 
						|
    if (tls_config_set_ciphers(cfg, "compat") == -1)
 | 
						|
        goto err_config;
 | 
						|
    if (c->ca_file && tls_config_set_ca_file(cfg, c->ca_file) == -1)
 | 
						|
        goto err_config;
 | 
						|
    if (c->cert_file && tls_config_set_cert_file(cfg, c->cert_file) == -1)
 | 
						|
        goto err_config;
 | 
						|
    if (c->key_file && tls_config_set_key_file(cfg, c->key_file) == -1)
 | 
						|
        goto err_config;
 | 
						|
    if (!c->verify) {
 | 
						|
        tls_config_insecure_noverifycert(cfg);
 | 
						|
        tls_config_insecure_noverifyname(cfg);
 | 
						|
        tls_config_insecure_noverifytime(cfg);
 | 
						|
    }
 | 
						|
    if (tls_configure(p->ctx, cfg) == -1)
 | 
						|
        goto err_ctx;
 | 
						|
 | 
						|
    if (!c->listen) {
 | 
						|
        ret = tls_connect_cbs(p->ctx, tls_read_callback, tls_write_callback,
 | 
						|
            c->tcp, c->host);
 | 
						|
    } else {
 | 
						|
        struct tls *ctx_new;
 | 
						|
        ret = tls_accept_cbs(p->ctx, &ctx_new, tls_read_callback,
 | 
						|
            tls_write_callback, c->tcp);
 | 
						|
        if (ret == 0) {
 | 
						|
            // free "server" context and replace by "connection" context
 | 
						|
            tls_free(p->ctx);
 | 
						|
            p->ctx = ctx_new;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (ret == -1)
 | 
						|
        goto err_ctx;
 | 
						|
 | 
						|
    tls_config_free(cfg);
 | 
						|
    return 0;
 | 
						|
err_config:
 | 
						|
    av_log(h, AV_LOG_ERROR, "%s\n", tls_config_error(cfg));
 | 
						|
    ret = AVERROR(EIO);
 | 
						|
    goto fail;
 | 
						|
err_ctx:
 | 
						|
    av_log(h, AV_LOG_ERROR, "%s\n", tls_error(p->ctx));
 | 
						|
    ret = AVERROR(EIO);
 | 
						|
    /* fallthrough */
 | 
						|
fail:
 | 
						|
    if (cfg)
 | 
						|
        tls_config_free(cfg);
 | 
						|
    ff_tls_close(h);
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
static int ff_tls_read(URLContext *h, uint8_t *buf, int size)
 | 
						|
{
 | 
						|
    TLSContext *p = h->priv_data;
 | 
						|
    ssize_t ret;
 | 
						|
    ret = tls_read(p->ctx, buf, size);
 | 
						|
    if (ret > 0)
 | 
						|
        return ret;
 | 
						|
    else if (ret == 0)
 | 
						|
        return AVERROR_EOF;
 | 
						|
    else if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT)
 | 
						|
        return AVERROR(EAGAIN);
 | 
						|
    av_log(h, AV_LOG_ERROR, "%s\n", tls_error(p->ctx));
 | 
						|
    return AVERROR(EIO);
 | 
						|
}
 | 
						|
 | 
						|
static int ff_tls_write(URLContext *h, const uint8_t *buf, int size)
 | 
						|
{
 | 
						|
    TLSContext *p = h->priv_data;
 | 
						|
    ssize_t ret;
 | 
						|
    ret = tls_write(p->ctx, buf, size);
 | 
						|
    if (ret > 0)
 | 
						|
        return ret;
 | 
						|
    else if (ret == 0)
 | 
						|
        return AVERROR_EOF;
 | 
						|
    else if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT)
 | 
						|
        return AVERROR(EAGAIN);
 | 
						|
    av_log(h, AV_LOG_ERROR, "%s\n", tls_error(p->ctx));
 | 
						|
    return AVERROR(EIO);
 | 
						|
}
 | 
						|
 | 
						|
static int tls_get_file_handle(URLContext *h)
 | 
						|
{
 | 
						|
    TLSContext *c = h->priv_data;
 | 
						|
    return ffurl_get_file_handle(c->tls_shared.tcp);
 | 
						|
}
 | 
						|
 | 
						|
static int tls_get_short_seek(URLContext *h)
 | 
						|
{
 | 
						|
    TLSContext *s = h->priv_data;
 | 
						|
    return ffurl_get_short_seek(s->tls_shared.tcp);
 | 
						|
}
 | 
						|
 | 
						|
static const AVOption options[] = {
 | 
						|
    TLS_COMMON_OPTIONS(TLSContext, tls_shared),
 | 
						|
    { NULL }
 | 
						|
};
 | 
						|
 | 
						|
static const AVClass tls_class = {
 | 
						|
    .class_name = "tls",
 | 
						|
    .item_name  = av_default_item_name,
 | 
						|
    .option     = options,
 | 
						|
    .version    = LIBAVUTIL_VERSION_INT,
 | 
						|
};
 | 
						|
 | 
						|
const URLProtocol ff_tls_protocol = {
 | 
						|
    .name           = "tls",
 | 
						|
    .url_open2      = ff_tls_open,
 | 
						|
    .url_read       = ff_tls_read,
 | 
						|
    .url_write      = ff_tls_write,
 | 
						|
    .url_close      = ff_tls_close,
 | 
						|
    .url_get_file_handle = tls_get_file_handle,
 | 
						|
    .url_get_short_seek  = tls_get_short_seek,
 | 
						|
    .priv_data_size = sizeof(TLSContext),
 | 
						|
    .flags          = URL_PROTOCOL_FLAG_NETWORK,
 | 
						|
    .priv_data_class = &tls_class,
 | 
						|
};
 |