LCOV - code coverage report
Current view: top level - libavformat - network.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 47 150 31.3 %
Date: 2017-12-15 11:05:35 Functions: 6 15 40.0 %

          Line data    Source code
       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 <fcntl.h>
      22             : #include "network.h"
      23             : #include "tls.h"
      24             : #include "url.h"
      25             : #include "libavcodec/internal.h"
      26             : #include "libavutil/avutil.h"
      27             : #include "libavutil/mem.h"
      28             : #include "libavutil/time.h"
      29             : 
      30        5466 : int ff_tls_init(void)
      31             : {
      32             : #if CONFIG_TLS_PROTOCOL
      33             : #if CONFIG_OPENSSL
      34             :     int ret;
      35             :     if ((ret = ff_openssl_init()) < 0)
      36             :         return ret;
      37             : #endif
      38             : #if CONFIG_GNUTLS
      39             :     ff_gnutls_init();
      40             : #endif
      41             : #endif
      42        5466 :     return 0;
      43             : }
      44             : 
      45        5466 : void ff_tls_deinit(void)
      46             : {
      47             : #if CONFIG_TLS_PROTOCOL
      48             : #if CONFIG_OPENSSL
      49             :     ff_openssl_deinit();
      50             : #endif
      51             : #if CONFIG_GNUTLS
      52             :     ff_gnutls_deinit();
      53             : #endif
      54             : #endif
      55        5466 : }
      56             : 
      57             : int ff_network_inited_globally;
      58             : 
      59        5466 : int ff_network_init(void)
      60             : {
      61             : #if HAVE_WINSOCK2_H
      62             :     WSADATA wsaData;
      63             : #endif
      64             : 
      65        5466 :     if (!ff_network_inited_globally)
      66           0 :         av_log(NULL, AV_LOG_WARNING, "Using network protocols without global "
      67             :                                      "network initialization. Please use "
      68             :                                      "avformat_network_init(), this will "
      69             :                                      "become mandatory later.\n");
      70             : #if HAVE_WINSOCK2_H
      71             :     if (WSAStartup(MAKEWORD(1,1), &wsaData))
      72             :         return 0;
      73             : #endif
      74        5466 :     return 1;
      75             : }
      76             : 
      77           0 : int ff_network_wait_fd(int fd, int write)
      78             : {
      79           0 :     int ev = write ? POLLOUT : POLLIN;
      80           0 :     struct pollfd p = { .fd = fd, .events = ev, .revents = 0 };
      81             :     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             : }
      85             : 
      86           0 : int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb)
      87             : {
      88             :     int ret;
      89           0 :     int64_t wait_start = 0;
      90             : 
      91             :     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             :         }
     103             :     }
     104             : }
     105             : 
     106        5466 : void ff_network_close(void)
     107             : {
     108             : #if HAVE_WINSOCK2_H
     109             :     WSACleanup();
     110             : #endif
     111        5466 : }
     112             : 
     113             : #if HAVE_WINSOCK2_H
     114             : int ff_neterrno(void)
     115             : {
     116             :     int err = WSAGetLastError();
     117             :     switch (err) {
     118             :     case WSAEWOULDBLOCK:
     119             :         return AVERROR(EAGAIN);
     120             :     case WSAEINTR:
     121             :         return AVERROR(EINTR);
     122             :     case WSAEPROTONOSUPPORT:
     123             :         return AVERROR(EPROTONOSUPPORT);
     124             :     case WSAETIMEDOUT:
     125             :         return AVERROR(ETIMEDOUT);
     126             :     case WSAECONNREFUSED:
     127             :         return AVERROR(ECONNREFUSED);
     128             :     case WSAEINPROGRESS:
     129             :         return AVERROR(EINPROGRESS);
     130             :     }
     131             :     return -err;
     132             : }
     133             : #endif
     134             : 
     135           0 : int ff_is_multicast_address(struct sockaddr *addr)
     136             : {
     137           0 :     if (addr->sa_family == AF_INET) {
     138           0 :         return IN_MULTICAST(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr));
     139             :     }
     140             : #if HAVE_STRUCT_SOCKADDR_IN6
     141           0 :     if (addr->sa_family == AF_INET6) {
     142           0 :         return IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)addr)->sin6_addr);
     143             :     }
     144             : #endif
     145             : 
     146           0 :     return 0;
     147             : }
     148             : 
     149           0 : static int ff_poll_interrupt(struct pollfd *p, nfds_t nfds, int timeout,
     150             :                              AVIOInterruptCB *cb)
     151             : {
     152           0 :     int runs = timeout / POLLING_TIME;
     153           0 :     int ret = 0;
     154             : 
     155             :     do {
     156           0 :         if (ff_check_interrupt(cb))
     157           0 :             return AVERROR_EXIT;
     158           0 :         ret = poll(p, nfds, POLLING_TIME);
     159           0 :         if (ret != 0)
     160           0 :             break;
     161           0 :     } while (timeout <= 0 || runs-- > 0);
     162             : 
     163           0 :     if (!ret)
     164           0 :         return AVERROR(ETIMEDOUT);
     165           0 :     if (ret < 0)
     166           0 :         return ff_neterrno();
     167           0 :     return ret;
     168             : }
     169             : 
     170           0 : int ff_socket(int af, int type, int proto)
     171             : {
     172             :     int fd;
     173             : 
     174             : #ifdef SOCK_CLOEXEC
     175           0 :     fd = socket(af, type | SOCK_CLOEXEC, proto);
     176           0 :     if (fd == -1 && errno == EINVAL)
     177             : #endif
     178             :     {
     179           0 :         fd = socket(af, type, proto);
     180             : #if HAVE_FCNTL
     181           0 :         if (fd != -1) {
     182           0 :             if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
     183           0 :                 av_log(NULL, AV_LOG_DEBUG, "Failed to set close on exec\n");
     184             :         }
     185             : #endif
     186             :     }
     187             : #ifdef SO_NOSIGPIPE
     188             :     if (fd != -1)
     189             :         setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){1}, sizeof(int));
     190             : #endif
     191           0 :     return fd;
     192             : }
     193             : 
     194           0 : int ff_listen(int fd, const struct sockaddr *addr,
     195             :               socklen_t addrlen)
     196             : {
     197             :     int ret;
     198           0 :     int reuse = 1;
     199           0 :     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) {
     200           0 :         av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_REUSEADDR) failed\n");
     201             :     }
     202           0 :     ret = bind(fd, addr, addrlen);
     203           0 :     if (ret)
     204           0 :         return ff_neterrno();
     205             : 
     206           0 :     ret = listen(fd, 1);
     207           0 :     if (ret)
     208           0 :         return ff_neterrno();
     209           0 :     return ret;
     210             : }
     211             : 
     212           0 : int ff_accept(int fd, int timeout, URLContext *h)
     213             : {
     214             :     int ret;
     215           0 :     struct pollfd lp = { fd, POLLIN, 0 };
     216             : 
     217           0 :     ret = ff_poll_interrupt(&lp, 1, timeout, &h->interrupt_callback);
     218           0 :     if (ret < 0)
     219           0 :         return ret;
     220             : 
     221           0 :     ret = accept(fd, NULL, NULL);
     222           0 :     if (ret < 0)
     223           0 :         return ff_neterrno();
     224           0 :     if (ff_socket_nonblock(ret, 1) < 0)
     225           0 :         av_log(NULL, AV_LOG_DEBUG, "ff_socket_nonblock failed\n");
     226             : 
     227           0 :     return ret;
     228             : }
     229             : 
     230           0 : int ff_listen_bind(int fd, const struct sockaddr *addr,
     231             :                    socklen_t addrlen, int timeout, URLContext *h)
     232             : {
     233             :     int ret;
     234           0 :     if ((ret = ff_listen(fd, addr, addrlen)) < 0)
     235           0 :         return ret;
     236           0 :     if ((ret = ff_accept(fd, timeout, h)) < 0)
     237           0 :         return ret;
     238           0 :     closesocket(fd);
     239           0 :     return ret;
     240             : }
     241             : 
     242           0 : int ff_listen_connect(int fd, const struct sockaddr *addr,
     243             :                       socklen_t addrlen, int timeout, URLContext *h,
     244             :                       int will_try_next)
     245             : {
     246           0 :     struct pollfd p = {fd, POLLOUT, 0};
     247             :     int ret;
     248             :     socklen_t optlen;
     249             : 
     250           0 :     if (ff_socket_nonblock(fd, 1) < 0)
     251           0 :         av_log(NULL, AV_LOG_DEBUG, "ff_socket_nonblock failed\n");
     252             : 
     253           0 :     while ((ret = connect(fd, addr, addrlen))) {
     254           0 :         ret = ff_neterrno();
     255           0 :         switch (ret) {
     256           0 :         case AVERROR(EINTR):
     257           0 :             if (ff_check_interrupt(&h->interrupt_callback))
     258           0 :                 return AVERROR_EXIT;
     259           0 :             continue;
     260           0 :         case AVERROR(EINPROGRESS):
     261             :         case AVERROR(EAGAIN):
     262           0 :             ret = ff_poll_interrupt(&p, 1, timeout, &h->interrupt_callback);
     263           0 :             if (ret < 0)
     264           0 :                 return ret;
     265           0 :             optlen = sizeof(ret);
     266           0 :             if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen))
     267           0 :                 ret = AVUNERROR(ff_neterrno());
     268           0 :             if (ret != 0) {
     269             :                 char errbuf[100];
     270           0 :                 ret = AVERROR(ret);
     271           0 :                 av_strerror(ret, errbuf, sizeof(errbuf));
     272           0 :                 if (will_try_next)
     273           0 :                     av_log(h, AV_LOG_WARNING,
     274             :                            "Connection to %s failed (%s), trying next address\n",
     275             :                            h->filename, errbuf);
     276             :                 else
     277           0 :                     av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n",
     278             :                            h->filename, errbuf);
     279             :             }
     280             :         default:
     281           0 :             return ret;
     282             :         }
     283             :     }
     284           0 :     return ret;
     285             : }
     286             : 
     287          15 : static int match_host_pattern(const char *pattern, const char *hostname)
     288             : {
     289             :     int len_p, len_h;
     290          15 :     if (!strcmp(pattern, "*"))
     291           1 :         return 1;
     292             :     // Skip a possible *. at the start of the pattern
     293          14 :     if (pattern[0] == '*')
     294           2 :         pattern++;
     295          14 :     if (pattern[0] == '.')
     296           3 :         pattern++;
     297          14 :     len_p = strlen(pattern);
     298          14 :     len_h = strlen(hostname);
     299          14 :     if (len_p > len_h)
     300           5 :         return 0;
     301             :     // Simply check if the end of hostname is equal to 'pattern'
     302           9 :     if (!strcmp(pattern, &hostname[len_h - len_p])) {
     303           6 :         if (len_h == len_p)
     304           4 :             return 1; // Exact match
     305           2 :         if (hostname[len_h - len_p - 1] == '.')
     306           1 :             return 1; // The matched substring is a domain and not just a substring of a domain
     307             :     }
     308           4 :     return 0;
     309             : }
     310             : 
     311           9 : int ff_http_match_no_proxy(const char *no_proxy, const char *hostname)
     312             : {
     313             :     char *buf, *start;
     314           9 :     int ret = 0;
     315           9 :     if (!no_proxy)
     316           1 :         return 0;
     317           8 :     if (!hostname)
     318           0 :         return 0;
     319           8 :     buf = av_strdup(no_proxy);
     320           8 :     if (!buf)
     321           0 :         return 0;
     322           8 :     start = buf;
     323          25 :     while (start) {
     324          15 :         char *sep, *next = NULL;
     325          15 :         start += strspn(start, " ,");
     326          15 :         sep = start + strcspn(start, " ,");
     327          15 :         if (*sep) {
     328           7 :             next = sep + 1;
     329           7 :             *sep = '\0';
     330             :         }
     331          15 :         if (match_host_pattern(start, hostname)) {
     332           6 :             ret = 1;
     333           6 :             break;
     334             :         }
     335           9 :         start = next;
     336             :     }
     337           8 :     av_free(buf);
     338           8 :     return ret;
     339             : }

Generated by: LCOV version 1.13