FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/network.c
Date: 2026-05-01 13:04:54
Exec Total Coverage
Lines: 46 290 15.9%
Functions: 6 21 28.6%
Branches: 24 178 13.5%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2007 The FFmpeg Project
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "config.h"
22 #include "config_components.h"
23 #include "libavutil/attributes.h"
24
25 #if CONFIG_TLS_PROTOCOL && CONFIG_OPENSSL
26 #include <openssl/opensslv.h>
27 #endif
28
29 #include <fcntl.h>
30 #include "network.h"
31 #include "tls.h"
32 #include "url.h"
33 #include "libavutil/avassert.h"
34 #include "libavutil/mem.h"
35 #include "libavutil/time.h"
36
37 8751 int ff_tls_init(void)
38 {
39 #if CONFIG_TLS_PROTOCOL
40 #if CONFIG_GNUTLS
41 ff_gnutls_init();
42 #endif
43 #endif
44 8751 return 0;
45 }
46
47 8751 void ff_tls_deinit(void)
48 {
49 #if CONFIG_TLS_PROTOCOL
50 #if CONFIG_GNUTLS
51 ff_gnutls_deinit();
52 #endif
53 #endif
54 8751 }
55
56 8751 int ff_network_init(void)
57 {
58 #if HAVE_WINSOCK2_H
59 WSADATA wsaData;
60
61 if (WSAStartup(MAKEWORD(1,1), &wsaData))
62 return 0;
63 #endif
64 8751 return 1;
65 }
66
67 int ff_network_wait_fd(int fd, int write)
68 {
69 int ev = write ? POLLOUT : POLLIN;
70 struct pollfd p = { .fd = fd, .events = ev, .revents = 0 };
71 int ret;
72 ret = poll(&p, 1, POLLING_TIME);
73 return ret < 0 ? ff_neterrno() : p.revents & (ev | POLLERR | POLLHUP) ? 0 : AVERROR(EAGAIN);
74 }
75
76 int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb)
77 {
78 int ret;
79 int64_t wait_start = 0;
80
81 while (1) {
82 if (ff_check_interrupt(int_cb))
83 return AVERROR_EXIT;
84 ret = ff_network_wait_fd(fd, write);
85 if (ret != AVERROR(EAGAIN))
86 return ret;
87 if (timeout > 0) {
88 if (!wait_start)
89 wait_start = av_gettime_relative();
90 else if (av_gettime_relative() - wait_start > timeout)
91 return AVERROR(ETIMEDOUT);
92 }
93 }
94 }
95
96 int ff_network_sleep_interruptible(int64_t timeout, AVIOInterruptCB *int_cb)
97 {
98 int64_t wait_start = av_gettime_relative();
99
100 while (1) {
101 int64_t time_left;
102
103 if (ff_check_interrupt(int_cb))
104 return AVERROR_EXIT;
105
106 time_left = timeout - (av_gettime_relative() - wait_start);
107 if (time_left <= 0)
108 return AVERROR(ETIMEDOUT);
109
110 av_usleep(FFMIN(time_left, POLLING_TIME * 1000));
111 }
112 }
113
114 8751 void ff_network_close(void)
115 {
116 #if HAVE_WINSOCK2_H
117 WSACleanup();
118 #endif
119 8751 }
120
121 #if HAVE_WINSOCK2_H
122 int ff_neterrno(void)
123 {
124 int err = WSAGetLastError();
125 switch (err) {
126 case WSAEWOULDBLOCK:
127 return AVERROR(EAGAIN);
128 case WSAEINTR:
129 return AVERROR(EINTR);
130 case WSAEPROTONOSUPPORT:
131 return AVERROR(EPROTONOSUPPORT);
132 case WSAETIMEDOUT:
133 return AVERROR(ETIMEDOUT);
134 case WSAECONNREFUSED:
135 return AVERROR(ECONNREFUSED);
136 case WSAEINPROGRESS:
137 return AVERROR(EINPROGRESS);
138 }
139 return -err;
140 }
141 #endif
142
143 int ff_is_multicast_address(struct sockaddr *addr)
144 {
145 if (addr->sa_family == AF_INET) {
146 return IN_MULTICAST(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr));
147 }
148 #if HAVE_STRUCT_SOCKADDR_IN6
149 if (addr->sa_family == AF_INET6) {
150 return IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)addr)->sin6_addr);
151 }
152 #endif
153
154 return 0;
155 }
156
157 static int ff_poll_interrupt(struct pollfd *p, nfds_t nfds, int timeout,
158 AVIOInterruptCB *cb)
159 {
160 int runs = timeout / POLLING_TIME;
161 int ret = 0;
162
163 do {
164 if (ff_check_interrupt(cb))
165 return AVERROR_EXIT;
166 ret = poll(p, nfds, POLLING_TIME);
167 if (ret != 0) {
168 if (ret < 0)
169 ret = ff_neterrno();
170 if (ret == AVERROR(EINTR))
171 continue;
172 break;
173 }
174 } while (timeout <= 0 || runs-- > 0);
175
176 if (!ret)
177 return AVERROR(ETIMEDOUT);
178 return ret;
179 }
180
181 int ff_socket(int af, int type, int proto, void *logctx)
182 {
183 int fd;
184
185 #ifdef SOCK_CLOEXEC
186 fd = socket(af, type | SOCK_CLOEXEC, proto);
187 if (fd == -1 && errno == EINVAL)
188 #endif
189 {
190 fd = socket(af, type, proto);
191 #if HAVE_FCNTL
192 if (fd != -1) {
193 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
194 av_log(logctx, AV_LOG_DEBUG, "Failed to set close on exec\n");
195 }
196 #endif
197 }
198 #ifdef SO_NOSIGPIPE
199 if (fd != -1) {
200 if (setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){1}, sizeof(int))) {
201 av_log(logctx, AV_LOG_WARNING, "setsockopt(SO_NOSIGPIPE) failed\n");
202 }
203 }
204 #endif
205 return fd;
206 }
207
208 int ff_listen(int fd, const struct sockaddr *addr,
209 socklen_t addrlen, void *logctx)
210 {
211 int ret;
212 int reuse = 1;
213 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) {
214 av_log(logctx, AV_LOG_WARNING, "setsockopt(SO_REUSEADDR) failed\n");
215 }
216 ret = bind(fd, addr, addrlen);
217 if (ret)
218 return ff_neterrno();
219
220 ret = listen(fd, 1);
221 if (ret)
222 return ff_neterrno();
223 return ret;
224 }
225
226 int ff_accept(int fd, int timeout, URLContext *h)
227 {
228 int ret;
229 struct pollfd lp = { fd, POLLIN, 0 };
230
231 ret = ff_poll_interrupt(&lp, 1, timeout, &h->interrupt_callback);
232 if (ret < 0)
233 return ret;
234
235 ret = accept(fd, NULL, NULL);
236 if (ret < 0)
237 return ff_neterrno();
238 if (ff_socket_nonblock(ret, 1) < 0)
239 av_log(h, AV_LOG_DEBUG, "ff_socket_nonblock failed\n");
240
241 return ret;
242 }
243
244 int ff_listen_bind(int fd, const struct sockaddr *addr,
245 socklen_t addrlen, int timeout, URLContext *h)
246 {
247 int ret;
248 if ((ret = ff_listen(fd, addr, addrlen, h)) < 0)
249 return ret;
250 if ((ret = ff_accept(fd, timeout, h)) < 0)
251 return ret;
252 closesocket(fd);
253 return ret;
254 }
255
256 int ff_listen_connect(int fd, const struct sockaddr *addr,
257 socklen_t addrlen, int timeout, URLContext *h,
258 int will_try_next)
259 {
260 struct pollfd p = {fd, POLLOUT, 0};
261 int ret;
262 socklen_t optlen;
263
264 if (ff_socket_nonblock(fd, 1) < 0)
265 av_log(h, AV_LOG_DEBUG, "ff_socket_nonblock failed\n");
266
267 while ((ret = connect(fd, addr, addrlen))) {
268 ret = ff_neterrno();
269 switch (ret) {
270 case AVERROR(EINTR):
271 if (ff_check_interrupt(&h->interrupt_callback))
272 return AVERROR_EXIT;
273 continue;
274 case AVERROR(EINPROGRESS):
275 case AVERROR(EAGAIN):
276 ret = ff_poll_interrupt(&p, 1, timeout, &h->interrupt_callback);
277 if (ret < 0)
278 return ret;
279 optlen = sizeof(ret);
280 if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen))
281 ret = AVUNERROR(ff_neterrno());
282 if (ret != 0) {
283 ret = AVERROR(ret);
284 if (will_try_next)
285 av_log(h, AV_LOG_WARNING,
286 "Connection to %s failed (%s), trying next address\n",
287 h->filename, av_err2str(ret));
288 else
289 av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n",
290 h->filename, av_err2str(ret));
291 }
292 av_fallthrough;
293 default:
294 return ret;
295 }
296 }
297 return ret;
298 }
299
300 static void interleave_addrinfo(struct addrinfo *base)
301 {
302 struct addrinfo **next = &base->ai_next;
303 while (*next) {
304 struct addrinfo *cur = *next;
305 // Iterate forward until we find an entry of a different family.
306 if (cur->ai_family == base->ai_family) {
307 next = &cur->ai_next;
308 continue;
309 }
310 if (cur == base->ai_next) {
311 // If the first one following base is of a different family, just
312 // move base forward one step and continue.
313 base = cur;
314 next = &base->ai_next;
315 continue;
316 }
317 // Unchain cur from the rest of the list from its current spot.
318 *next = cur->ai_next;
319 // Hook in cur directly after base.
320 cur->ai_next = base->ai_next;
321 base->ai_next = cur;
322 // Restart with a new base. We know that before moving the cur element,
323 // everything between the previous base and cur had the same family,
324 // different from cur->ai_family. Therefore, we can keep next pointing
325 // where it was, and continue from there with base at the one after
326 // cur.
327 base = cur->ai_next;
328 }
329 }
330
331 static void print_address_list(void *ctx, const struct addrinfo *addr,
332 const char *title)
333 {
334 char hostbuf[100], portbuf[20];
335 av_log(ctx, AV_LOG_DEBUG, "%s:\n", title);
336 while (addr) {
337 getnameinfo(addr->ai_addr, addr->ai_addrlen,
338 hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf),
339 NI_NUMERICHOST | NI_NUMERICSERV);
340 av_log(ctx, AV_LOG_DEBUG, "Address %s port %s\n", hostbuf, portbuf);
341 addr = addr->ai_next;
342 }
343 }
344
345 struct ConnectionAttempt {
346 int fd;
347 int64_t deadline_us;
348 struct addrinfo *addr;
349 };
350
351 // Returns < 0 on error, 0 on successfully started connection attempt,
352 // > 0 for a connection that succeeded already.
353 static int start_connect_attempt(struct ConnectionAttempt *attempt,
354 struct addrinfo **ptr, int timeout_ms,
355 URLContext *h,
356 int (*customize_fd)(void *, int, int), void *customize_ctx)
357 {
358 struct addrinfo *ai = *ptr;
359 int ret;
360
361 *ptr = ai->ai_next;
362
363 attempt->fd = ff_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol, h);
364 if (attempt->fd < 0)
365 return ff_neterrno();
366 attempt->deadline_us = av_gettime_relative() + timeout_ms * 1000;
367 attempt->addr = ai;
368
369 ff_socket_nonblock(attempt->fd, 1);
370
371 if (customize_fd) {
372 ret = customize_fd(customize_ctx, attempt->fd, ai->ai_family);
373 if (ret) {
374 closesocket(attempt->fd);
375 attempt->fd = -1;
376 return ret;
377 }
378 }
379
380 while ((ret = connect(attempt->fd, ai->ai_addr, ai->ai_addrlen))) {
381 ret = ff_neterrno();
382 switch (ret) {
383 case AVERROR(EINTR):
384 if (ff_check_interrupt(&h->interrupt_callback)) {
385 closesocket(attempt->fd);
386 attempt->fd = -1;
387 return AVERROR_EXIT;
388 }
389 continue;
390 case AVERROR(EINPROGRESS):
391 case AVERROR(EAGAIN):
392 return 0;
393 default:
394 closesocket(attempt->fd);
395 attempt->fd = -1;
396 return ret;
397 }
398 }
399 return 1;
400 }
401
402 // Try a new connection to another address after 200 ms, as suggested in
403 // RFC 8305 (or sooner if an earlier attempt fails).
404 #define NEXT_ATTEMPT_DELAY_MS 200
405
406 int ff_connect_parallel(struct addrinfo *addrs, int timeout_ms_per_address,
407 int parallel, URLContext *h, int *fd,
408 int (*customize_fd)(void *, int, int), void *customize_ctx)
409 {
410 struct ConnectionAttempt attempts[3];
411 struct pollfd pfd[3];
412 int nb_attempts = 0, i, j;
413 int64_t next_attempt_us = av_gettime_relative(), next_deadline_us;
414 int last_err = AVERROR(EIO);
415 socklen_t optlen;
416 char hostbuf[100], portbuf[20];
417
418 if (parallel > FF_ARRAY_ELEMS(attempts))
419 parallel = FF_ARRAY_ELEMS(attempts);
420
421 print_address_list(h, addrs, "Original list of addresses");
422 // This mutates the list, but the head of the list is still the same
423 // element, so the caller, who owns the list, doesn't need to get
424 // an updated pointer.
425 interleave_addrinfo(addrs);
426 print_address_list(h, addrs, "Interleaved list of addresses");
427
428 while (nb_attempts > 0 || addrs) {
429 // Start a new connection attempt, if possible.
430 if (nb_attempts < parallel && addrs) {
431 getnameinfo(addrs->ai_addr, addrs->ai_addrlen,
432 hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf),
433 NI_NUMERICHOST | NI_NUMERICSERV);
434 av_log(h, AV_LOG_VERBOSE, "Starting connection attempt to %s port %s\n",
435 hostbuf, portbuf);
436 last_err = start_connect_attempt(&attempts[nb_attempts], &addrs,
437 timeout_ms_per_address, h,
438 customize_fd, customize_ctx);
439 if (last_err < 0) {
440 av_log(h, AV_LOG_VERBOSE, "Connected attempt failed: %s\n",
441 av_err2str(last_err));
442 continue;
443 }
444 if (last_err > 0) {
445 for (i = 0; i < nb_attempts; i++)
446 closesocket(attempts[i].fd);
447 *fd = attempts[nb_attempts].fd;
448 return 0;
449 }
450 pfd[nb_attempts].fd = attempts[nb_attempts].fd;
451 pfd[nb_attempts].events = POLLOUT;
452 next_attempt_us = av_gettime_relative() + NEXT_ATTEMPT_DELAY_MS * 1000;
453 nb_attempts++;
454 }
455
456 av_assert0(nb_attempts > 0);
457 // The connection attempts are sorted from oldest to newest, so the
458 // first one will have the earliest deadline.
459 next_deadline_us = attempts[0].deadline_us;
460 // If we can start another attempt in parallel, wait until that time.
461 if (nb_attempts < parallel && addrs)
462 next_deadline_us = FFMIN(next_deadline_us, next_attempt_us);
463 last_err = ff_poll_interrupt(pfd, nb_attempts,
464 (next_deadline_us - av_gettime_relative())/1000,
465 &h->interrupt_callback);
466 if (last_err < 0 && last_err != AVERROR(ETIMEDOUT))
467 break;
468
469 // Check the status from the poll output.
470 for (i = 0; i < nb_attempts; i++) {
471 last_err = 0;
472 if (pfd[i].revents) {
473 // Some sort of action for this socket, check its status (either
474 // a successful connection or an error).
475 optlen = sizeof(last_err);
476 if (getsockopt(attempts[i].fd, SOL_SOCKET, SO_ERROR, &last_err, &optlen))
477 last_err = ff_neterrno();
478 else if (last_err != 0)
479 last_err = AVERROR(last_err);
480 if (last_err == 0) {
481 // Everything is ok, we seem to have a successful
482 // connection. Close other sockets and return this one.
483 for (j = 0; j < nb_attempts; j++)
484 if (j != i)
485 closesocket(attempts[j].fd);
486 *fd = attempts[i].fd;
487 getnameinfo(attempts[i].addr->ai_addr, attempts[i].addr->ai_addrlen,
488 hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf),
489 NI_NUMERICHOST | NI_NUMERICSERV);
490 av_log(h, AV_LOG_VERBOSE, "Successfully connected to %s port %s\n",
491 hostbuf, portbuf);
492 return 0;
493 }
494 }
495 if (attempts[i].deadline_us < av_gettime_relative() && !last_err)
496 last_err = AVERROR(ETIMEDOUT);
497 if (!last_err)
498 continue;
499 // Error (or timeout) for this socket; close the socket and remove
500 // it from the attempts/pfd arrays, to let a new attempt start
501 // directly.
502 getnameinfo(attempts[i].addr->ai_addr, attempts[i].addr->ai_addrlen,
503 hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf),
504 NI_NUMERICHOST | NI_NUMERICSERV);
505 av_log(h, AV_LOG_VERBOSE, "Connection attempt to %s port %s "
506 "failed: %s\n", hostbuf, portbuf, av_err2str(last_err));
507 closesocket(attempts[i].fd);
508 memmove(&attempts[i], &attempts[i + 1],
509 (nb_attempts - i - 1) * sizeof(*attempts));
510 memmove(&pfd[i], &pfd[i + 1],
511 (nb_attempts - i - 1) * sizeof(*pfd));
512 i--;
513 nb_attempts--;
514 }
515 }
516 for (i = 0; i < nb_attempts; i++)
517 closesocket(attempts[i].fd);
518 if (last_err >= 0)
519 last_err = AVERROR(ECONNREFUSED);
520 if (last_err != AVERROR_EXIT) {
521 av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n",
522 h->filename, av_err2str(last_err));
523 }
524 return last_err;
525 }
526
527 15 static int match_host_pattern(const char *pattern, const char *hostname)
528 {
529 int len_p, len_h;
530
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 14 times.
15 if (!strcmp(pattern, "*"))
531 1 return 1;
532 // Skip a possible *. at the start of the pattern
533
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
14 if (pattern[0] == '*')
534 2 pattern++;
535
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 11 times.
14 if (pattern[0] == '.')
536 3 pattern++;
537 14 len_p = strlen(pattern);
538 14 len_h = strlen(hostname);
539
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 9 times.
14 if (len_p > len_h)
540 5 return 0;
541 // Simply check if the end of hostname is equal to 'pattern'
542
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
9 if (!strcmp(pattern, &hostname[len_h - len_p])) {
543
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (len_h == len_p)
544 4 return 1; // Exact match
545
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (hostname[len_h - len_p - 1] == '.')
546 1 return 1; // The matched substring is a domain and not just a substring of a domain
547 }
548 4 return 0;
549 }
550
551 9 int ff_http_match_no_proxy(const char *no_proxy, const char *hostname)
552 {
553 char *buf, *start;
554 9 int ret = 0;
555
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 if (!no_proxy)
556 1 return 0;
557
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!hostname)
558 return 0;
559 8 buf = av_strdup(no_proxy);
560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!buf)
561 return 0;
562 8 start = buf;
563
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 2 times.
17 while (start) {
564 15 char *sep, *next = NULL;
565 15 start += strspn(start, " ,");
566 15 sep = start + strcspn(start, " ,");
567
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 8 times.
15 if (*sep) {
568 7 next = sep + 1;
569 7 *sep = '\0';
570 }
571
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 9 times.
15 if (match_host_pattern(start, hostname)) {
572 6 ret = 1;
573 6 break;
574 }
575 9 start = next;
576 }
577 8 av_free(buf);
578 8 return ret;
579 }
580
581 void ff_log_net_error(void *ctx, int level, const char* prefix)
582 {
583 av_log(ctx, level, "%s: %s\n", prefix, av_err2str(ff_neterrno()));
584 }
585