Coverage Report

Created: 2026-10-28 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavformat/network.c
Line
Count
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 <string.h>
22
23
#include "config.h"
24
#include "config_components.h"
25
#include "libavutil/attributes.h"
26
27
#if CONFIG_TLS_PROTOCOL && CONFIG_OPENSSL
28
#include <openssl/opensslv.h>
29
#endif
30
31
#include <fcntl.h>
32
#if HAVE_EVENTFD
33
#include <sys/eventfd.h>
34
#endif
35
#include "network.h"
36
#include "tls.h"
37
#include "url.h"
38
#include "libavutil/avassert.h"
39
#include "libavutil/mem.h"
40
#include "libavutil/time.h"
41
42
int ff_tls_init(void)
43
0
{
44
#if CONFIG_TLS_PROTOCOL
45
#if CONFIG_GNUTLS
46
    ff_gnutls_init();
47
#endif
48
#endif
49
0
    return 0;
50
0
}
51
52
void ff_tls_deinit(void)
53
0
{
54
#if CONFIG_TLS_PROTOCOL
55
#if CONFIG_GNUTLS
56
    ff_gnutls_deinit();
57
#endif
58
#endif
59
0
}
60
61
/**
62
 * Initialize the network subsystem. On Windows, this calls WSAStartup().
63
 *
64
 * @return 0 on success, a negative AVERROR code on failure.
65
 */
66
int ff_network_init(void)
67
0
{
68
#if HAVE_WINSOCK2_H
69
    WSADATA wsaData;
70
71
    if (WSAStartup(MAKEWORD(1,1), &wsaData))
72
        return AVERROR(EIO);
73
#endif
74
0
    return 0;
75
0
}
76
77
int ff_network_wait_fd(int fd, int write)
78
0
{
79
0
    int ev = write ? POLLOUT : POLLIN;
80
0
    struct pollfd p = { .fd = fd, .events = ev, .revents = 0 };
81
0
    int ret;
82
0
    ret = poll(&p, 1, POLLING_TIME);
83
0
    return ret < 0 ? ff_neterrno() : p.revents & (ev | POLLERR | POLLHUP) ? 0 : AVERROR(EAGAIN);
84
0
}
85
86
int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb)
87
0
{
88
0
    int ret;
89
0
    int64_t wait_start = 0;
90
91
0
    while (1) {
92
0
        if (ff_check_interrupt(int_cb))
93
0
            return AVERROR_EXIT;
94
0
        ret = ff_network_wait_fd(fd, write);
95
0
        if (ret != AVERROR(EAGAIN))
96
0
            return ret;
97
0
        if (timeout > 0) {
98
0
            if (!wait_start)
99
0
                wait_start = av_gettime_relative();
100
0
            else if (av_gettime_relative() - wait_start > timeout)
101
0
                return AVERROR(ETIMEDOUT);
102
0
        }
103
0
    }
104
0
}
105
106
int ff_network_wakeup_open(FFNetWakeup *w)
107
0
{
108
#if HAVE_WINSOCK2_H
109
    /* select() and WSAPoll() only accept sockets, so use a datagram socket
110
     * connected to itself: sending a datagram to it makes it readable.
111
     */
112
    struct sockaddr_in addr = { .sin_family = AF_INET };
113
    socklen_t len = sizeof(addr);
114
    int ret, fd = ff_socket(AF_INET, SOCK_DGRAM, 0, NULL);
115
116
    if (fd < 0)
117
        return ff_neterrno();
118
119
    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
120
    if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0 ||
121
        getsockname(fd, (struct sockaddr *)&addr, &len) < 0 ||
122
        connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
123
        ret = ff_neterrno();
124
        closesocket(fd);
125
        return ret;
126
    }
127
128
    w->rfd = w->wfd = fd;
129
#elif HAVE_EVENTFD
130
0
    int fd = eventfd(0, EFD_CLOEXEC);
131
132
0
    if (fd < 0)
133
0
        return AVERROR(errno);
134
135
0
    w->rfd = w->wfd = fd;
136
#else
137
    int fds[2];
138
139
    if (pipe(fds) < 0)
140
        return AVERROR(errno);
141
142
#if HAVE_FCNTL
143
    for (int i = 0; i < 2; i++) {
144
        if (fcntl(fds[i], F_SETFD, FD_CLOEXEC) < 0) {
145
            int ret = AVERROR(errno);
146
            closesocket(fds[0]);
147
            closesocket(fds[1]);
148
            return ret;
149
        }
150
    }
151
#endif
152
153
    w->rfd = fds[0];
154
    w->wfd = fds[1];
155
#endif
156
157
0
    atomic_init(&w->signaled, 0);
158
159
0
    return 0;
160
0
}
161
162
int ff_network_wakeup_signal(FFNetWakeup *w)
163
0
{
164
    /* An eventfd only accepts 8-byte writes; a pipe or a socket takes any
165
     * payload, so the same value serves every channel type.
166
     */
167
0
    const uint64_t one = 1;
168
0
    int ret;
169
170
    /* wfd is blocking; writing at most once keeps the write from blocking.
171
     * The flag publishes no other data, so relaxed ordering is enough.
172
     */
173
0
    if (atomic_exchange_explicit(&w->signaled, 1, memory_order_relaxed))
174
0
        return 0;
175
176
#if HAVE_WINSOCK2_H
177
    ret = send(w->wfd, (const char *)&one, sizeof(one), 0);
178
#else
179
0
    ret = write(w->wfd, &one, sizeof(one));
180
0
#endif
181
182
0
    return ret < 0 ? ff_neterrno() : 0;
183
0
}
184
185
void ff_network_wakeup_close(FFNetWakeup *w)
186
0
{
187
0
    if (w->wfd != w->rfd)
188
0
        closesocket(w->wfd);
189
0
    closesocket(w->rfd);
190
191
0
    w->rfd = w->wfd = -1;
192
0
}
193
194
int ff_network_wait_fd_wakeup(int fd, int write, int timeout_ms,
195
                              const FFNetWakeup *w)
196
0
{
197
0
    int ev = write ? POLLOUT : POLLIN;
198
0
    struct pollfd p[2] = {
199
0
        { .fd = w->rfd, .events = POLLIN },
200
0
        { .fd = fd,     .events = ev },
201
0
    };
202
0
    int ret;
203
204
    /* Return without polling once signaled. This also ends the wait when
205
     * the write in ff_network_wakeup_signal() failed and rfd never became
206
     * readable.
207
     */
208
0
    if (atomic_load_explicit(&w->signaled, memory_order_relaxed))
209
0
        return AVERROR_EXIT;
210
211
0
    ret = poll(p, 2, timeout_ms);
212
0
    if (ret < 0)
213
0
        return ff_neterrno();
214
215
0
    if (p[0].revents & POLLIN)
216
0
        return AVERROR_EXIT;
217
218
0
    return p[1].revents & (ev | POLLERR | POLLHUP) ? 0 : AVERROR(EAGAIN);
219
0
}
220
221
int ff_network_sleep_interruptible(int64_t timeout, AVIOInterruptCB *int_cb)
222
0
{
223
0
    int64_t wait_start = av_gettime_relative();
224
225
0
    while (1) {
226
0
        int64_t time_left;
227
228
0
        if (ff_check_interrupt(int_cb))
229
0
            return AVERROR_EXIT;
230
231
0
        time_left = timeout - (av_gettime_relative() - wait_start);
232
0
        if (time_left <= 0)
233
0
            return AVERROR(ETIMEDOUT);
234
235
0
        av_usleep(FFMIN(time_left, POLLING_TIME * 1000));
236
0
    }
237
0
}
238
239
void ff_network_close(void)
240
0
{
241
#if HAVE_WINSOCK2_H
242
    WSACleanup();
243
#endif
244
0
}
245
246
#if HAVE_WINSOCK2_H
247
int ff_neterrno(void)
248
{
249
    int err = WSAGetLastError();
250
    switch (err) {
251
    case WSAEWOULDBLOCK:
252
        return AVERROR(EAGAIN);
253
    case WSAEINTR:
254
        return AVERROR(EINTR);
255
    case WSAEPROTONOSUPPORT:
256
        return AVERROR(EPROTONOSUPPORT);
257
    case WSAETIMEDOUT:
258
        return AVERROR(ETIMEDOUT);
259
    case WSAECONNREFUSED:
260
        return AVERROR(ECONNREFUSED);
261
    case WSAEINPROGRESS:
262
        return AVERROR(EINPROGRESS);
263
    }
264
    return -err;
265
}
266
#endif
267
268
int ff_is_multicast_address(struct sockaddr *addr)
269
0
{
270
0
    if (addr->sa_family == AF_INET) {
271
0
        return IN_MULTICAST(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr));
272
0
    }
273
0
#if HAVE_STRUCT_SOCKADDR_IN6
274
0
    if (addr->sa_family == AF_INET6) {
275
0
        return IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)addr)->sin6_addr);
276
0
    }
277
0
#endif
278
279
0
    return 0;
280
0
}
281
282
static int ff_poll_interrupt(struct pollfd *p, nfds_t nfds, int timeout,
283
                             AVIOInterruptCB *cb)
284
0
{
285
0
    int runs = timeout / POLLING_TIME;
286
0
    int ret = 0;
287
288
0
    do {
289
0
        if (ff_check_interrupt(cb))
290
0
            return AVERROR_EXIT;
291
0
        ret = poll(p, nfds, POLLING_TIME);
292
0
        if (ret != 0) {
293
0
            if (ret < 0)
294
0
                ret = ff_neterrno();
295
0
            if (ret == AVERROR(EINTR))
296
0
                continue;
297
0
            break;
298
0
        }
299
0
    } while (timeout <= 0 || runs-- > 0);
300
301
0
    if (!ret)
302
0
        return AVERROR(ETIMEDOUT);
303
0
    return ret;
304
0
}
305
306
int ff_socket(int af, int type, int proto, void *logctx)
307
0
{
308
0
    int fd;
309
310
0
#ifdef SOCK_CLOEXEC
311
0
    fd = socket(af, type | SOCK_CLOEXEC, proto);
312
0
    if (fd == -1 && errno == EINVAL)
313
0
#endif
314
0
    {
315
0
        fd = socket(af, type, proto);
316
0
#if HAVE_FCNTL
317
0
        if (fd != -1) {
318
0
            if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
319
0
                av_log(logctx, AV_LOG_DEBUG, "Failed to set close on exec\n");
320
0
        }
321
0
#endif
322
0
    }
323
#ifdef SO_NOSIGPIPE
324
    if (fd != -1) {
325
        if (setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){1}, sizeof(int))) {
326
             av_log(logctx, AV_LOG_WARNING, "setsockopt(SO_NOSIGPIPE) failed\n");
327
        }
328
    }
329
#endif
330
0
    return fd;
331
0
}
332
333
int ff_listen(int fd, const struct sockaddr *addr,
334
              socklen_t addrlen, void *logctx)
335
0
{
336
0
    int ret;
337
0
    int reuse = 1;
338
0
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) {
339
0
        av_log(logctx, AV_LOG_WARNING, "setsockopt(SO_REUSEADDR) failed\n");
340
0
    }
341
0
    ret = bind(fd, addr, addrlen);
342
0
    if (ret)
343
0
        return ff_neterrno();
344
345
0
    ret = listen(fd, 1);
346
0
    if (ret)
347
0
        return ff_neterrno();
348
0
    return ret;
349
0
}
350
351
int ff_accept(int fd, int timeout, URLContext *h)
352
0
{
353
0
    int ret;
354
0
    struct pollfd lp = { fd, POLLIN, 0 };
355
356
0
    ret = ff_poll_interrupt(&lp, 1, timeout, &h->interrupt_callback);
357
0
    if (ret < 0)
358
0
        return ret;
359
360
0
    ret = accept(fd, NULL, NULL);
361
0
    if (ret < 0)
362
0
        return ff_neterrno();
363
0
    if (ff_socket_nonblock(ret, 1) < 0)
364
0
        av_log(h, AV_LOG_DEBUG, "ff_socket_nonblock failed\n");
365
366
0
    return ret;
367
0
}
368
369
int ff_listen_bind(int fd, const struct sockaddr *addr,
370
                   socklen_t addrlen, int timeout, URLContext *h)
371
0
{
372
0
    int ret;
373
0
    if ((ret = ff_listen(fd, addr, addrlen, h)) < 0)
374
0
        return ret;
375
0
    if ((ret = ff_accept(fd, timeout, h)) < 0)
376
0
        return ret;
377
0
    closesocket(fd);
378
0
    return ret;
379
0
}
380
381
int ff_listen_connect(int fd, const struct sockaddr *addr,
382
                      socklen_t addrlen, int timeout, URLContext *h,
383
                      int will_try_next)
384
0
{
385
0
    struct pollfd p = {fd, POLLOUT, 0};
386
0
    int ret;
387
0
    socklen_t optlen;
388
389
0
    if (ff_socket_nonblock(fd, 1) < 0)
390
0
        av_log(h, AV_LOG_DEBUG, "ff_socket_nonblock failed\n");
391
392
0
    while ((ret = connect(fd, addr, addrlen))) {
393
0
        ret = ff_neterrno();
394
0
        switch (ret) {
395
0
        case AVERROR(EINTR):
396
0
            if (ff_check_interrupt(&h->interrupt_callback))
397
0
                return AVERROR_EXIT;
398
0
            continue;
399
0
        case AVERROR(EINPROGRESS):
400
0
        case AVERROR(EAGAIN):
401
0
            ret = ff_poll_interrupt(&p, 1, timeout, &h->interrupt_callback);
402
0
            if (ret < 0)
403
0
                return ret;
404
0
            optlen = sizeof(ret);
405
0
            if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen))
406
0
                ret = AVUNERROR(ff_neterrno());
407
0
            if (ret != 0) {
408
0
                ret = AVERROR(ret);
409
0
                if (will_try_next)
410
0
                    av_log(h, AV_LOG_WARNING,
411
0
                           "Connection to %s failed (%s), trying next address\n",
412
0
                           h->filename, av_err2str(ret));
413
0
                else
414
0
                    av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n",
415
0
                           h->filename, av_err2str(ret));
416
0
            }
417
0
            av_fallthrough;
418
0
        default:
419
0
            return ret;
420
0
        }
421
0
    }
422
0
    return ret;
423
0
}
424
425
static void interleave_addrinfo(struct addrinfo *base)
426
0
{
427
0
    struct addrinfo **next = &base->ai_next;
428
0
    while (*next) {
429
0
        struct addrinfo *cur = *next;
430
        // Iterate forward until we find an entry of a different family.
431
0
        if (cur->ai_family == base->ai_family) {
432
0
            next = &cur->ai_next;
433
0
            continue;
434
0
        }
435
0
        if (cur == base->ai_next) {
436
            // If the first one following base is of a different family, just
437
            // move base forward one step and continue.
438
0
            base = cur;
439
0
            next = &base->ai_next;
440
0
            continue;
441
0
        }
442
        // Unchain cur from the rest of the list from its current spot.
443
0
        *next = cur->ai_next;
444
        // Hook in cur directly after base.
445
0
        cur->ai_next = base->ai_next;
446
0
        base->ai_next = cur;
447
        // Restart with a new base. We know that before moving the cur element,
448
        // everything between the previous base and cur had the same family,
449
        // different from cur->ai_family. Therefore, we can keep next pointing
450
        // where it was, and continue from there with base at the one after
451
        // cur.
452
0
        base = cur->ai_next;
453
0
    }
454
0
}
455
456
static void print_address_list(void *ctx, const struct addrinfo *addr,
457
                               const char *title)
458
0
{
459
0
    char hostbuf[100], portbuf[20];
460
0
    av_log(ctx, AV_LOG_DEBUG, "%s:\n", title);
461
0
    while (addr) {
462
0
        getnameinfo(addr->ai_addr, addr->ai_addrlen,
463
0
                    hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf),
464
0
                    NI_NUMERICHOST | NI_NUMERICSERV);
465
0
        av_log(ctx, AV_LOG_DEBUG, "Address %s port %s\n", hostbuf, portbuf);
466
0
        addr = addr->ai_next;
467
0
    }
468
0
}
469
470
struct ConnectionAttempt {
471
    int fd;
472
    int64_t deadline_us;
473
    struct addrinfo *addr;
474
};
475
476
// Returns < 0 on error, 0 on successfully started connection attempt,
477
// > 0 for a connection that succeeded already.
478
static int start_connect_attempt(struct ConnectionAttempt *attempt,
479
                                 struct addrinfo **ptr, int timeout_ms,
480
                                 URLContext *h,
481
                                 int (*customize_fd)(void *, int, int), void *customize_ctx)
482
0
{
483
0
    struct addrinfo *ai = *ptr;
484
0
    int ret;
485
486
0
    *ptr = ai->ai_next;
487
488
0
    attempt->fd = ff_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol, h);
489
0
    if (attempt->fd < 0)
490
0
        return ff_neterrno();
491
0
    attempt->deadline_us = av_gettime_relative() + timeout_ms * 1000;
492
0
    attempt->addr = ai;
493
494
0
    ff_socket_nonblock(attempt->fd, 1);
495
496
0
    if (customize_fd) {
497
0
        ret = customize_fd(customize_ctx, attempt->fd, ai->ai_family);
498
0
        if (ret) {
499
0
            closesocket(attempt->fd);
500
0
            attempt->fd = -1;
501
0
            return ret;
502
0
        }
503
0
    }
504
505
0
    while ((ret = connect(attempt->fd, ai->ai_addr, ai->ai_addrlen))) {
506
0
        ret = ff_neterrno();
507
0
        switch (ret) {
508
0
        case AVERROR(EINTR):
509
0
            if (ff_check_interrupt(&h->interrupt_callback)) {
510
0
                closesocket(attempt->fd);
511
0
                attempt->fd = -1;
512
0
                return AVERROR_EXIT;
513
0
            }
514
0
            continue;
515
0
        case AVERROR(EINPROGRESS):
516
0
        case AVERROR(EAGAIN):
517
0
            return 0;
518
0
        default:
519
0
            closesocket(attempt->fd);
520
0
            attempt->fd = -1;
521
0
            return ret;
522
0
        }
523
0
    }
524
0
    return 1;
525
0
}
526
527
// Try a new connection to another address after 200 ms, as suggested in
528
// RFC 8305 (or sooner if an earlier attempt fails).
529
0
#define NEXT_ATTEMPT_DELAY_MS 200
530
531
int ff_connect_parallel(struct addrinfo *addrs, int timeout_ms_per_address,
532
                        int parallel, URLContext *h, int *fd,
533
                        int (*customize_fd)(void *, int, int), void *customize_ctx)
534
0
{
535
0
    struct ConnectionAttempt attempts[3];
536
0
    struct pollfd pfd[3];
537
0
    int nb_attempts = 0, i, j;
538
0
    int64_t next_attempt_us = av_gettime_relative(), next_deadline_us;
539
0
    int last_err = AVERROR(EIO);
540
0
    socklen_t optlen;
541
0
    char hostbuf[100], portbuf[20];
542
543
0
    if (parallel > FF_ARRAY_ELEMS(attempts))
544
0
        parallel = FF_ARRAY_ELEMS(attempts);
545
546
0
    print_address_list(h, addrs, "Original list of addresses");
547
    // This mutates the list, but the head of the list is still the same
548
    // element, so the caller, who owns the list, doesn't need to get
549
    // an updated pointer.
550
0
    interleave_addrinfo(addrs);
551
0
    print_address_list(h, addrs, "Interleaved list of addresses");
552
553
0
    while (nb_attempts > 0 || addrs) {
554
        // Start a new connection attempt, if possible.
555
0
        if (nb_attempts < parallel && addrs) {
556
0
            getnameinfo(addrs->ai_addr, addrs->ai_addrlen,
557
0
                        hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf),
558
0
                        NI_NUMERICHOST | NI_NUMERICSERV);
559
0
            av_log(h, AV_LOG_VERBOSE, "Starting connection attempt to %s port %s\n",
560
0
                                      hostbuf, portbuf);
561
0
            last_err = start_connect_attempt(&attempts[nb_attempts], &addrs,
562
0
                                             timeout_ms_per_address, h,
563
0
                                             customize_fd, customize_ctx);
564
0
            if (last_err < 0) {
565
0
                av_log(h, AV_LOG_VERBOSE, "Connected attempt failed: %s\n",
566
0
                                          av_err2str(last_err));
567
0
                continue;
568
0
            }
569
0
            if (last_err > 0) {
570
0
                for (i = 0; i < nb_attempts; i++)
571
0
                    closesocket(attempts[i].fd);
572
0
                *fd = attempts[nb_attempts].fd;
573
0
                return 0;
574
0
            }
575
0
            pfd[nb_attempts].fd = attempts[nb_attempts].fd;
576
0
            pfd[nb_attempts].events = POLLOUT;
577
0
            next_attempt_us = av_gettime_relative() + NEXT_ATTEMPT_DELAY_MS * 1000;
578
0
            nb_attempts++;
579
0
        }
580
581
0
        av_assert0(nb_attempts > 0);
582
        // The connection attempts are sorted from oldest to newest, so the
583
        // first one will have the earliest deadline.
584
0
        next_deadline_us = attempts[0].deadline_us;
585
        // If we can start another attempt in parallel, wait until that time.
586
0
        if (nb_attempts < parallel && addrs)
587
0
            next_deadline_us = FFMIN(next_deadline_us, next_attempt_us);
588
0
        last_err = ff_poll_interrupt(pfd, nb_attempts,
589
0
                                     (next_deadline_us - av_gettime_relative())/1000,
590
0
                                     &h->interrupt_callback);
591
0
        if (last_err < 0 && last_err != AVERROR(ETIMEDOUT))
592
0
            break;
593
594
        // Check the status from the poll output.
595
0
        for (i = 0; i < nb_attempts; i++) {
596
0
            last_err = 0;
597
0
            if (pfd[i].revents) {
598
                // Some sort of action for this socket, check its status (either
599
                // a successful connection or an error).
600
0
                optlen = sizeof(last_err);
601
0
                if (getsockopt(attempts[i].fd, SOL_SOCKET, SO_ERROR, &last_err, &optlen))
602
0
                    last_err = ff_neterrno();
603
0
                else if (last_err != 0)
604
0
                    last_err = AVERROR(last_err);
605
0
                if (last_err == 0) {
606
                    // Everything is ok, we seem to have a successful
607
                    // connection. Close other sockets and return this one.
608
0
                    for (j = 0; j < nb_attempts; j++)
609
0
                        if (j != i)
610
0
                            closesocket(attempts[j].fd);
611
0
                    *fd = attempts[i].fd;
612
0
                    getnameinfo(attempts[i].addr->ai_addr, attempts[i].addr->ai_addrlen,
613
0
                                hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf),
614
0
                                NI_NUMERICHOST | NI_NUMERICSERV);
615
0
                    av_log(h, AV_LOG_VERBOSE, "Successfully connected to %s port %s\n",
616
0
                                              hostbuf, portbuf);
617
0
                    return 0;
618
0
                }
619
0
            }
620
0
            if (attempts[i].deadline_us < av_gettime_relative() && !last_err)
621
0
                last_err = AVERROR(ETIMEDOUT);
622
0
            if (!last_err)
623
0
                continue;
624
            // Error (or timeout) for this socket; close the socket and remove
625
            // it from the attempts/pfd arrays, to let a new attempt start
626
            // directly.
627
0
            getnameinfo(attempts[i].addr->ai_addr, attempts[i].addr->ai_addrlen,
628
0
                        hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf),
629
0
                        NI_NUMERICHOST | NI_NUMERICSERV);
630
0
            av_log(h, AV_LOG_VERBOSE, "Connection attempt to %s port %s "
631
0
                                      "failed: %s\n", hostbuf, portbuf, av_err2str(last_err));
632
0
            closesocket(attempts[i].fd);
633
0
            memmove(&attempts[i], &attempts[i + 1],
634
0
                    (nb_attempts - i - 1) * sizeof(*attempts));
635
0
            memmove(&pfd[i], &pfd[i + 1],
636
0
                    (nb_attempts - i - 1) * sizeof(*pfd));
637
0
            i--;
638
0
            nb_attempts--;
639
0
        }
640
0
    }
641
0
    for (i = 0; i < nb_attempts; i++)
642
0
        closesocket(attempts[i].fd);
643
0
    if (last_err >= 0)
644
0
        last_err = AVERROR(ECONNREFUSED);
645
0
    if (last_err != AVERROR_EXIT) {
646
0
        av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n",
647
0
               h->filename, av_err2str(last_err));
648
0
    }
649
0
    return last_err;
650
0
}
651
652
static int match_host_pattern(const char *pattern, const char *hostname)
653
0
{
654
0
    int len_p, len_h;
655
0
    if (!strcmp(pattern, "*"))
656
0
        return 1;
657
    // Skip a possible *. at the start of the pattern
658
0
    if (pattern[0] == '*')
659
0
        pattern++;
660
0
    if (pattern[0] == '.')
661
0
        pattern++;
662
0
    len_p = strlen(pattern);
663
0
    len_h = strlen(hostname);
664
0
    if (len_p > len_h)
665
0
        return 0;
666
    // Simply check if the end of hostname is equal to 'pattern'
667
0
    if (!strcmp(pattern, &hostname[len_h - len_p])) {
668
0
        if (len_h == len_p)
669
0
            return 1; // Exact match
670
0
        if (hostname[len_h - len_p - 1] == '.')
671
0
            return 1; // The matched substring is a domain and not just a substring of a domain
672
0
    }
673
0
    return 0;
674
0
}
675
676
int ff_http_match_no_proxy(const char *no_proxy, const char *hostname)
677
0
{
678
0
    char *buf, *start;
679
0
    int ret = 0;
680
0
    if (!no_proxy)
681
0
        return 0;
682
0
    if (!hostname)
683
0
        return 0;
684
0
    buf = av_strdup(no_proxy);
685
0
    if (!buf)
686
0
        return 0;
687
0
    start = buf;
688
0
    while (start) {
689
0
        char *sep, *next = NULL;
690
0
        start += strspn(start, " ,");
691
0
        sep = start + strcspn(start, " ,");
692
0
        if (*sep) {
693
0
            next = sep + 1;
694
0
            *sep = '\0';
695
0
        }
696
0
        if (match_host_pattern(start, hostname)) {
697
0
            ret = 1;
698
0
            break;
699
0
        }
700
0
        start = next;
701
0
    }
702
0
    av_free(buf);
703
0
    return ret;
704
0
}
705
706
void ff_log_net_error(void *ctx, int level, const char* prefix)
707
0
{
708
0
    av_log(ctx, level, "%s: %s\n", prefix, av_err2str(ff_neterrno()));
709
0
}