tools/sofa2wavs: fix build on Windows
[ffmpeg.git] / libavformat / tls.c
1 /*
2 * TLS/DTLS/SSL Protocol
3 * Copyright (c) 2011 Martin Storsjo
4 * Copyright (c) 2025 Jack Lau
5 *
6 * This file is part of FFmpeg.
7 *
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.
12 *
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.
17 *
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
21 */
22
23 #include "avformat.h"
24 #include "internal.h"
25 #include "network.h"
26 #include "os_support.h"
27 #include "url.h"
28 #include "tls.h"
29 #include "libavutil/avstring.h"
30 #include "libavutil/getenv_utf8.h"
31 #include "libavutil/mem.h"
32 #include "libavutil/parseutils.h"
33
34 int ff_tls_open_underlying(TLSShared *c, URLContext *parent, const char *uri, AVDictionary **options)
35 {
36 int port;
37 const char *p;
38 char buf[200], opts[50] = "";
39 struct addrinfo hints = { 0 }, *ai = NULL;
40 const char *proxy_path;
41 char *env_http_proxy, *env_no_proxy;
42 int use_proxy;
43 int ret;
44
45 p = strchr(uri, '?');
46 if (p) {
47 ret = ff_parse_opts_from_query_string(c, p, 1);
48 if (ret < 0)
49 return ret;
50 }
51
52 if (c->listen && !c->is_dtls)
53 snprintf(opts, sizeof(opts), "?listen=1");
54
55 av_url_split(NULL, 0, NULL, 0, c->underlying_host, sizeof(c->underlying_host), &port, NULL, 0, uri);
56
57 if (!p) {
58 p = opts;
59 } else {
60 if (av_find_info_tag(opts, sizeof(opts), "listen", p))
61 c->listen = 1;
62 }
63
64 ff_url_join(buf, sizeof(buf), c->is_dtls ? "udp" : "tcp", NULL, (c->is_dtls && c->listen) ? "" : c->underlying_host, port, "%s", p);
65
66 hints.ai_flags = AI_NUMERICHOST;
67 if (!getaddrinfo(c->underlying_host, NULL, &hints, &ai)) {
68 c->numerichost = 1;
69 freeaddrinfo(ai);
70 }
71
72 if (!c->host && !(c->host = av_strdup(c->underlying_host)))
73 return AVERROR(ENOMEM);
74
75 env_http_proxy = getenv_utf8("http_proxy");
76 proxy_path = c->http_proxy ? c->http_proxy : env_http_proxy;
77
78 env_no_proxy = getenv_utf8("no_proxy");
79 use_proxy = !ff_http_match_no_proxy(env_no_proxy, c->underlying_host) &&
80 proxy_path && av_strstart(proxy_path, "http://", NULL);
81 freeenv_utf8(env_no_proxy);
82
83 if (!c->is_dtls && use_proxy) {
84 char proxy_host[200], proxy_auth[200], dest[200];
85 int proxy_port;
86 av_url_split(NULL, 0, proxy_auth, sizeof(proxy_auth),
87 proxy_host, sizeof(proxy_host), &proxy_port, NULL, 0,
88 proxy_path);
89 ff_url_join(dest, sizeof(dest), NULL, NULL, c->underlying_host, port, NULL);
90 ff_url_join(buf, sizeof(buf), "httpproxy", proxy_auth, proxy_host,
91 proxy_port, "/%s", dest);
92 }
93
94 freeenv_utf8(env_http_proxy);
95 if (c->is_dtls) {
96 if (c->listen) {
97 av_dict_set_int(options, "localport", port, 0);
98 av_dict_set(options, "localaddr", c->underlying_host, 0);
99 } else {
100 av_dict_set_int(options, "localport", 0, 0);
101 av_dict_set_int(options, "connect", 1, 0);
102 }
103 av_dict_set_int(options, "fifo_size", 0, 0);
104 /* Set the max packet size to the buffer size. */
105 av_dict_set_int(options, "pkt_size", c->mtu, 0);
106 }
107 ret = ffurl_open_whitelist(c->is_dtls ? &c->udp : &c->tcp, buf, AVIO_FLAG_READ_WRITE,
108 &parent->interrupt_callback, options,
109 parent->protocol_whitelist, parent->protocol_blacklist, parent);
110 return ret;
111 }
112
113 /**
114 * Read all data from the given URL url and store it in the given buffer bp.
115 */
116 int ff_url_read_all(const char *url, AVBPrint *bp)
117 {
118 int ret = 0;
119 AVDictionary *opts = NULL;
120 URLContext *uc = NULL;
121 char buf[MAX_URL_SIZE];
122
123 ret = ffurl_open_whitelist(&uc, url, AVIO_FLAG_READ, NULL, &opts, NULL, NULL, NULL);
124 if (ret < 0) {
125 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to open url %s\n", url);
126 goto end;
127 }
128
129 while (1) {
130 ret = ffurl_read(uc, buf, sizeof(buf));
131 if (ret == AVERROR_EOF) {
132 /* Reset the error because we read all response as answer util EOF. */
133 ret = 0;
134 break;
135 }
136 if (ret <= 0) {
137 av_log(NULL, AV_LOG_ERROR, "TLS: Failed to read from url=%s, key is %s\n", url, bp->str);
138 goto end;
139 }
140
141 av_bprintf(bp, "%.*s", ret, buf);
142 if (!av_bprint_is_complete(bp)) {
143 av_log(NULL, AV_LOG_ERROR, "TLS: Exceed max size %.*s, %s\n", ret, buf, bp->str);
144 ret = AVERROR(EIO);
145 goto end;
146 }
147 }
148
149 end:
150 ffurl_closep(&uc);
151 av_dict_free(&opts);
152 return ret;
153 }