3 * Copyright (c) 2011 Martin Storsjo
4 * Copyright (c) 2017 sfan5 <sfan5@live.de>
6 * This file is part of FFmpeg.
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 #include "libavcodec/internal.h"
29 #include "libavutil/avutil.h"
30 #include "libavutil/opt.h"
34 typedef struct TLSContext
{
39 static int ff_tls_close(URLContext
*h
)
41 TLSContext
*p
= h
->priv_data
;
46 ffurl_closep(&p
->tls_shared
.tcp
);
50 static ssize_t
tls_read_callback(struct tls
*ctx
, void *buf
, size_t buflen
, void *cb_arg
)
52 URLContext
*h
= (URLContext
*) cb_arg
;
53 int ret
= ffurl_read(h
, buf
, buflen
);
54 if (ret
== AVERROR(EAGAIN
))
55 return TLS_WANT_POLLIN
;
56 else if (ret
== AVERROR_EXIT
)
58 return ret
>= 0 ? ret
: -1;
61 static ssize_t
tls_write_callback(struct tls
*ctx
, const void *buf
, size_t buflen
, void *cb_arg
)
63 URLContext
*h
= (URLContext
*) cb_arg
;
64 int ret
= ffurl_write(h
, buf
, buflen
);
65 if (ret
== AVERROR(EAGAIN
))
66 return TLS_WANT_POLLOUT
;
67 else if (ret
== AVERROR_EXIT
)
69 return ret
>= 0 ? ret
: -1;
72 static int ff_tls_open(URLContext
*h
, const char *uri
, int flags
, AVDictionary
**options
)
74 TLSContext
*p
= h
->priv_data
;
75 TLSShared
*c
= &p
->tls_shared
;
76 struct tls_config
*cfg
= NULL
;
79 if (tls_init() == -1) {
84 if ((ret
= ff_tls_open_underlying(c
, h
, uri
, options
)) < 0)
87 p
->ctx
= !c
->listen
? tls_client() : tls_server();
93 cfg
= tls_config_new();
98 if (tls_config_set_protocols(cfg
, TLS_PROTOCOLS_ALL
) == -1)
100 // While TLSv1.0 and TLSv1.1 are already enabled by the above,
101 // we need to be less strict with ciphers so it works in practice.
102 if (tls_config_set_ciphers(cfg
, "compat") == -1)
104 if (c
->ca_file
&& tls_config_set_ca_file(cfg
, c
->ca_file
) == -1)
106 if (c
->cert_file
&& tls_config_set_cert_file(cfg
, c
->cert_file
) == -1)
108 if (c
->key_file
&& tls_config_set_key_file(cfg
, c
->key_file
) == -1)
111 tls_config_insecure_noverifycert(cfg
);
112 tls_config_insecure_noverifyname(cfg
);
113 tls_config_insecure_noverifytime(cfg
);
115 if (tls_configure(p
->ctx
, cfg
) == -1)
119 ret
= tls_connect_cbs(p
->ctx
, tls_read_callback
, tls_write_callback
,
123 ret
= tls_accept_cbs(p
->ctx
, &ctx_new
, tls_read_callback
,
124 tls_write_callback
, c
->tcp
);
126 // free "server" context and replace by "connection" context
134 tls_config_free(cfg
);
137 av_log(h
, AV_LOG_ERROR
, "%s\n", tls_config_error(cfg
));
141 av_log(h
, AV_LOG_ERROR
, "%s\n", tls_error(p
->ctx
));
146 tls_config_free(cfg
);
151 static int ff_tls_read(URLContext
*h
, uint8_t *buf
, int size
)
153 TLSContext
*p
= h
->priv_data
;
155 ret
= tls_read(p
->ctx
, buf
, size
);
160 else if (ret
== TLS_WANT_POLLIN
|| ret
== TLS_WANT_POLLOUT
)
161 return AVERROR(EAGAIN
);
162 av_log(h
, AV_LOG_ERROR
, "%s\n", tls_error(p
->ctx
));
166 static int ff_tls_write(URLContext
*h
, const uint8_t *buf
, int size
)
168 TLSContext
*p
= h
->priv_data
;
170 ret
= tls_write(p
->ctx
, buf
, size
);
175 else if (ret
== TLS_WANT_POLLIN
|| ret
== TLS_WANT_POLLOUT
)
176 return AVERROR(EAGAIN
);
177 av_log(h
, AV_LOG_ERROR
, "%s\n", tls_error(p
->ctx
));
181 static int tls_get_file_handle(URLContext
*h
)
183 TLSContext
*c
= h
->priv_data
;
184 return ffurl_get_file_handle(c
->tls_shared
.tcp
);
187 static int tls_get_short_seek(URLContext
*h
)
189 TLSContext
*s
= h
->priv_data
;
190 return ffurl_get_short_seek(s
->tls_shared
.tcp
);
193 static const AVOption options
[] = {
194 TLS_COMMON_OPTIONS(TLSContext
, tls_shared
),
198 static const AVClass tls_class
= {
200 .item_name
= av_default_item_name
,
202 .version
= LIBAVUTIL_VERSION_INT
,
205 const URLProtocol ff_tls_protocol
= {
207 .url_open2
= ff_tls_open
,
208 .url_read
= ff_tls_read
,
209 .url_write
= ff_tls_write
,
210 .url_close
= ff_tls_close
,
211 .url_get_file_handle
= tls_get_file_handle
,
212 .url_get_short_seek
= tls_get_short_seek
,
213 .priv_data_size
= sizeof(TLSContext
),
214 .flags
= URL_PROTOCOL_FLAG_NETWORK
,
215 .priv_data_class
= &tls_class
,