LCOV - code coverage report
Current view: top level - libavformat - rtpproto.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 312 0.0 %
Date: 2017-12-16 13:57:32 Functions: 0 17 0.0 %

          Line data    Source code
       1             : /*
       2             :  * RTP network protocol
       3             :  * Copyright (c) 2002 Fabrice Bellard
       4             :  *
       5             :  * This file is part of FFmpeg.
       6             :  *
       7             :  * FFmpeg is free software; you can redistribute it and/or
       8             :  * modify it under the terms of the GNU Lesser General Public
       9             :  * License as published by the Free Software Foundation; either
      10             :  * version 2.1 of the License, or (at your option) any later version.
      11             :  *
      12             :  * FFmpeg is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :  * Lesser General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU Lesser General Public
      18             :  * License along with FFmpeg; if not, write to the Free Software
      19             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      20             :  */
      21             : 
      22             : /**
      23             :  * @file
      24             :  * RTP protocol
      25             :  */
      26             : 
      27             : #include "libavutil/parseutils.h"
      28             : #include "libavutil/avstring.h"
      29             : #include "libavutil/opt.h"
      30             : #include "avformat.h"
      31             : #include "avio_internal.h"
      32             : #include "rtp.h"
      33             : #include "rtpproto.h"
      34             : #include "url.h"
      35             : 
      36             : #include <stdarg.h>
      37             : #include "internal.h"
      38             : #include "network.h"
      39             : #include "os_support.h"
      40             : #include <fcntl.h>
      41             : #if HAVE_POLL_H
      42             : #include <sys/poll.h>
      43             : #endif
      44             : 
      45             : typedef struct RTPContext {
      46             :     const AVClass *class;
      47             :     URLContext *rtp_hd, *rtcp_hd, *fec_hd;
      48             :     int rtp_fd, rtcp_fd, nb_ssm_include_addrs, nb_ssm_exclude_addrs;
      49             :     struct sockaddr_storage **ssm_include_addrs, **ssm_exclude_addrs;
      50             :     int write_to_source;
      51             :     struct sockaddr_storage last_rtp_source, last_rtcp_source;
      52             :     socklen_t last_rtp_source_len, last_rtcp_source_len;
      53             :     int ttl;
      54             :     int buffer_size;
      55             :     int rtcp_port, local_rtpport, local_rtcpport;
      56             :     int connect;
      57             :     int pkt_size;
      58             :     int dscp;
      59             :     char *sources;
      60             :     char *block;
      61             :     char *fec_options_str;
      62             : } RTPContext;
      63             : 
      64             : #define OFFSET(x) offsetof(RTPContext, x)
      65             : #define D AV_OPT_FLAG_DECODING_PARAM
      66             : #define E AV_OPT_FLAG_ENCODING_PARAM
      67             : static const AVOption options[] = {
      68             :     { "ttl",                "Time to live (in milliseconds, multicast only)",                   OFFSET(ttl),             AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
      69             :     { "buffer_size",        "Send/Receive buffer size (in bytes)",                              OFFSET(buffer_size),     AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
      70             :     { "rtcp_port",          "Custom rtcp port",                                                 OFFSET(rtcp_port),       AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
      71             :     { "local_rtpport",      "Local rtp port",                                                   OFFSET(local_rtpport),   AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
      72             :     { "local_rtcpport",     "Local rtcp port",                                                  OFFSET(local_rtcpport),  AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
      73             :     { "connect",            "Connect socket",                                                   OFFSET(connect),         AV_OPT_TYPE_BOOL,   { .i64 =  0 },     0, 1,       .flags = D|E },
      74             :     { "write_to_source",    "Send packets to the source address of the latest received packet", OFFSET(write_to_source), AV_OPT_TYPE_BOOL,   { .i64 =  0 },     0, 1,       .flags = D|E },
      75             :     { "pkt_size",           "Maximum packet size",                                              OFFSET(pkt_size),        AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
      76             :     { "dscp",               "DSCP class",                                                       OFFSET(dscp),            AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
      77             :     { "sources",            "Source list",                                                      OFFSET(sources),         AV_OPT_TYPE_STRING, { .str = NULL },               .flags = D|E },
      78             :     { "block",              "Block list",                                                       OFFSET(block),           AV_OPT_TYPE_STRING, { .str = NULL },               .flags = D|E },
      79             :     { "fec",                "FEC",                                                              OFFSET(fec_options_str), AV_OPT_TYPE_STRING, { .str = NULL },               .flags = E },
      80             :     { NULL }
      81             : };
      82             : 
      83             : static const AVClass rtp_class = {
      84             :     .class_name = "rtp",
      85             :     .item_name  = av_default_item_name,
      86             :     .option     = options,
      87             :     .version    = LIBAVUTIL_VERSION_INT,
      88             : };
      89             : 
      90             : /**
      91             :  * If no filename is given to av_open_input_file because you want to
      92             :  * get the local port first, then you must call this function to set
      93             :  * the remote server address.
      94             :  *
      95             :  * @param h media file context
      96             :  * @param uri of the remote server
      97             :  * @return zero if no error.
      98             :  */
      99             : 
     100           0 : int ff_rtp_set_remote_url(URLContext *h, const char *uri)
     101             : {
     102           0 :     RTPContext *s = h->priv_data;
     103             :     char hostname[256];
     104             :     int port, rtcp_port;
     105             :     const char *p;
     106             : 
     107             :     char buf[1024];
     108             :     char path[1024];
     109             : 
     110           0 :     av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
     111             :                  path, sizeof(path), uri);
     112           0 :     rtcp_port = port + 1;
     113             : 
     114           0 :     p = strchr(uri, '?');
     115           0 :     if (p) {
     116           0 :         if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) {
     117           0 :             rtcp_port = strtol(buf, NULL, 10);
     118             :         }
     119             :     }
     120             : 
     121           0 :     ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port, "%s", path);
     122           0 :     ff_udp_set_remote_url(s->rtp_hd, buf);
     123             : 
     124           0 :     ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, rtcp_port, "%s", path);
     125           0 :     ff_udp_set_remote_url(s->rtcp_hd, buf);
     126           0 :     return 0;
     127             : }
     128             : 
     129           0 : static struct addrinfo* rtp_resolve_host(const char *hostname, int port,
     130             :                                          int type, int family, int flags)
     131             : {
     132           0 :     struct addrinfo hints = { 0 }, *res = 0;
     133             :     int error;
     134             :     char service[16];
     135             : 
     136           0 :     snprintf(service, sizeof(service), "%d", port);
     137           0 :     hints.ai_socktype = type;
     138           0 :     hints.ai_family   = family;
     139           0 :     hints.ai_flags    = flags;
     140           0 :     if ((error = getaddrinfo(hostname, service, &hints, &res))) {
     141           0 :         res = NULL;
     142           0 :         av_log(NULL, AV_LOG_ERROR, "rtp_resolve_host: %s\n", gai_strerror(error));
     143             :     }
     144             : 
     145           0 :     return res;
     146             : }
     147             : 
     148           0 : static int compare_addr(const struct sockaddr_storage *a,
     149             :                         const struct sockaddr_storage *b)
     150             : {
     151           0 :     if (a->ss_family != b->ss_family)
     152           0 :         return 1;
     153           0 :     if (a->ss_family == AF_INET) {
     154           0 :         return (((const struct sockaddr_in *)a)->sin_addr.s_addr !=
     155           0 :                 ((const struct sockaddr_in *)b)->sin_addr.s_addr);
     156             :     }
     157             : 
     158             : #if HAVE_STRUCT_SOCKADDR_IN6
     159           0 :     if (a->ss_family == AF_INET6) {
     160           0 :         const uint8_t *s6_addr_a = ((const struct sockaddr_in6 *)a)->sin6_addr.s6_addr;
     161           0 :         const uint8_t *s6_addr_b = ((const struct sockaddr_in6 *)b)->sin6_addr.s6_addr;
     162           0 :         return memcmp(s6_addr_a, s6_addr_b, 16);
     163             :     }
     164             : #endif
     165           0 :     return 1;
     166             : }
     167             : 
     168           0 : static int get_port(const struct sockaddr_storage *ss)
     169             : {
     170           0 :     if (ss->ss_family == AF_INET)
     171           0 :         return ntohs(((const struct sockaddr_in *)ss)->sin_port);
     172             : #if HAVE_STRUCT_SOCKADDR_IN6
     173           0 :     if (ss->ss_family == AF_INET6)
     174           0 :         return ntohs(((const struct sockaddr_in6 *)ss)->sin6_port);
     175             : #endif
     176           0 :     return 0;
     177             : }
     178             : 
     179           0 : static void set_port(struct sockaddr_storage *ss, int port)
     180             : {
     181           0 :     if (ss->ss_family == AF_INET)
     182           0 :         ((struct sockaddr_in *)ss)->sin_port = htons(port);
     183             : #if HAVE_STRUCT_SOCKADDR_IN6
     184           0 :     else if (ss->ss_family == AF_INET6)
     185           0 :         ((struct sockaddr_in6 *)ss)->sin6_port = htons(port);
     186             : #endif
     187           0 : }
     188             : 
     189           0 : static int rtp_check_source_lists(RTPContext *s, struct sockaddr_storage *source_addr_ptr)
     190             : {
     191             :     int i;
     192           0 :     if (s->nb_ssm_exclude_addrs) {
     193           0 :         for (i = 0; i < s->nb_ssm_exclude_addrs; i++) {
     194           0 :             if (!compare_addr(source_addr_ptr, s->ssm_exclude_addrs[i]))
     195           0 :                 return 1;
     196             :         }
     197             :     }
     198           0 :     if (s->nb_ssm_include_addrs) {
     199           0 :         for (i = 0; i < s->nb_ssm_include_addrs; i++) {
     200           0 :             if (!compare_addr(source_addr_ptr, s->ssm_include_addrs[i]))
     201           0 :                 return 0;
     202             :         }
     203           0 :         return 1;
     204             :     }
     205           0 :     return 0;
     206             : }
     207             : 
     208             : /**
     209             :  * add option to url of the form:
     210             :  * "http://host:port/path?option1=val1&option2=val2...
     211             :  */
     212             : 
     213           0 : static av_printf_format(3, 4) void url_add_option(char *buf, int buf_size, const char *fmt, ...)
     214             : {
     215             :     char buf1[1024];
     216             :     va_list ap;
     217             : 
     218           0 :     va_start(ap, fmt);
     219           0 :     if (strchr(buf, '?'))
     220           0 :         av_strlcat(buf, "&", buf_size);
     221             :     else
     222           0 :         av_strlcat(buf, "?", buf_size);
     223           0 :     vsnprintf(buf1, sizeof(buf1), fmt, ap);
     224           0 :     av_strlcat(buf, buf1, buf_size);
     225           0 :     va_end(ap);
     226           0 : }
     227             : 
     228           0 : static void build_udp_url(RTPContext *s,
     229             :                           char *buf, int buf_size,
     230             :                           const char *hostname,
     231             :                           int port, int local_port,
     232             :                           const char *include_sources,
     233             :                           const char *exclude_sources)
     234             : {
     235           0 :     ff_url_join(buf, buf_size, "udp", NULL, hostname, port, NULL);
     236           0 :     if (local_port >= 0)
     237           0 :         url_add_option(buf, buf_size, "localport=%d", local_port);
     238           0 :     if (s->ttl >= 0)
     239           0 :         url_add_option(buf, buf_size, "ttl=%d", s->ttl);
     240           0 :     if (s->buffer_size >= 0)
     241           0 :         url_add_option(buf, buf_size, "buffer_size=%d", s->buffer_size);
     242           0 :     if (s->pkt_size >= 0)
     243           0 :         url_add_option(buf, buf_size, "pkt_size=%d", s->pkt_size);
     244           0 :     if (s->connect)
     245           0 :         url_add_option(buf, buf_size, "connect=1");
     246           0 :     if (s->dscp >= 0)
     247           0 :         url_add_option(buf, buf_size, "dscp=%d", s->dscp);
     248           0 :     url_add_option(buf, buf_size, "fifo_size=0");
     249           0 :     if (include_sources && include_sources[0])
     250           0 :         url_add_option(buf, buf_size, "sources=%s", include_sources);
     251           0 :     if (exclude_sources && exclude_sources[0])
     252           0 :         url_add_option(buf, buf_size, "block=%s", exclude_sources);
     253           0 : }
     254             : 
     255           0 : static void rtp_parse_addr_list(URLContext *h, char *buf,
     256             :                                 struct sockaddr_storage ***address_list_ptr,
     257             :                                 int *address_list_size_ptr)
     258             : {
     259           0 :     struct addrinfo *ai = NULL;
     260             :     struct sockaddr_storage *source_addr;
     261           0 :     char tmp = '\0', *p = buf, *next;
     262             : 
     263             :     /* Resolve all of the IPs */
     264             : 
     265           0 :     while (p && p[0]) {
     266           0 :         next = strchr(p, ',');
     267             : 
     268           0 :         if (next) {
     269           0 :             tmp = *next;
     270           0 :             *next = '\0';
     271             :         }
     272             : 
     273           0 :         ai = rtp_resolve_host(p, 0, SOCK_DGRAM, AF_UNSPEC, 0);
     274           0 :         if (ai) {
     275           0 :             source_addr = av_mallocz(sizeof(struct sockaddr_storage));
     276           0 :             if (!source_addr) {
     277           0 :                 freeaddrinfo(ai);
     278           0 :                 break;
     279             :             }
     280             : 
     281           0 :             memcpy(source_addr, ai->ai_addr, ai->ai_addrlen);
     282           0 :             freeaddrinfo(ai);
     283           0 :             dynarray_add(address_list_ptr, address_list_size_ptr, source_addr);
     284             :         } else {
     285           0 :             av_log(h, AV_LOG_WARNING, "Unable to resolve %s\n", p);
     286             :         }
     287             : 
     288           0 :         if (next) {
     289           0 :             *next = tmp;
     290           0 :             p = next + 1;
     291             :         } else {
     292           0 :             p = NULL;
     293             :         }
     294             :     }
     295           0 : }
     296             : 
     297             : /**
     298             :  * url syntax: rtp://host:port[?option=val...]
     299             :  * option: 'ttl=n'            : set the ttl value (for multicast only)
     300             :  *         'rtcpport=n'       : set the remote rtcp port to n
     301             :  *         'localrtpport=n'   : set the local rtp port to n
     302             :  *         'localrtcpport=n'  : set the local rtcp port to n
     303             :  *         'pkt_size=n'       : set max packet size
     304             :  *         'connect=0/1'      : do a connect() on the UDP socket
     305             :  *         'sources=ip[,ip]'  : list allowed source IP addresses
     306             :  *         'block=ip[,ip]'    : list disallowed source IP addresses
     307             :  *         'write_to_source=0/1' : send packets to the source address of the latest received packet
     308             :  *         'dscp=n'           : set DSCP value to n (QoS)
     309             :  * deprecated option:
     310             :  *         'localport=n'      : set the local port to n
     311             :  *
     312             :  * if rtcpport isn't set the rtcp port will be the rtp port + 1
     313             :  * if local rtp port isn't set any available port will be used for the local
     314             :  * rtp and rtcp ports
     315             :  * if the local rtcp port is not set it will be the local rtp port + 1
     316             :  */
     317             : 
     318           0 : static int rtp_open(URLContext *h, const char *uri, int flags)
     319             : {
     320           0 :     RTPContext *s = h->priv_data;
     321           0 :     AVDictionary *fec_opts = NULL;
     322             :     int rtp_port;
     323           0 :     char hostname[256], include_sources[1024] = "", exclude_sources[1024] = "";
     324           0 :     char *sources = include_sources, *block = exclude_sources;
     325           0 :     char *fec_protocol = NULL;
     326             :     char buf[1024];
     327             :     char path[1024];
     328             :     const char *p;
     329           0 :     int i, max_retry_count = 3;
     330             :     int rtcpflags;
     331             : 
     332           0 :     av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port,
     333             :                  path, sizeof(path), uri);
     334             :     /* extract parameters */
     335           0 :     if (s->rtcp_port < 0)
     336           0 :         s->rtcp_port = rtp_port + 1;
     337             : 
     338           0 :     p = strchr(uri, '?');
     339           0 :     if (p) {
     340           0 :         if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) {
     341           0 :             s->ttl = strtol(buf, NULL, 10);
     342             :         }
     343           0 :         if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) {
     344           0 :             s->rtcp_port = strtol(buf, NULL, 10);
     345             :         }
     346           0 :         if (av_find_info_tag(buf, sizeof(buf), "localport", p)) {
     347           0 :             s->local_rtpport = strtol(buf, NULL, 10);
     348             :         }
     349           0 :         if (av_find_info_tag(buf, sizeof(buf), "localrtpport", p)) {
     350           0 :             s->local_rtpport = strtol(buf, NULL, 10);
     351             :         }
     352           0 :         if (av_find_info_tag(buf, sizeof(buf), "localrtcpport", p)) {
     353           0 :             s->local_rtcpport = strtol(buf, NULL, 10);
     354             :         }
     355           0 :         if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
     356           0 :             s->pkt_size = strtol(buf, NULL, 10);
     357             :         }
     358           0 :         if (av_find_info_tag(buf, sizeof(buf), "connect", p)) {
     359           0 :             s->connect = strtol(buf, NULL, 10);
     360             :         }
     361           0 :         if (av_find_info_tag(buf, sizeof(buf), "write_to_source", p)) {
     362           0 :             s->write_to_source = strtol(buf, NULL, 10);
     363             :         }
     364           0 :         if (av_find_info_tag(buf, sizeof(buf), "dscp", p)) {
     365           0 :             s->dscp = strtol(buf, NULL, 10);
     366             :         }
     367           0 :         if (av_find_info_tag(buf, sizeof(buf), "sources", p)) {
     368           0 :             av_strlcpy(include_sources, buf, sizeof(include_sources));
     369             : 
     370           0 :             rtp_parse_addr_list(h, buf, &s->ssm_include_addrs, &s->nb_ssm_include_addrs);
     371             :         } else {
     372           0 :             rtp_parse_addr_list(h, s->sources, &s->ssm_include_addrs, &s->nb_ssm_include_addrs);
     373           0 :             sources = s->sources;
     374             :         }
     375           0 :         if (av_find_info_tag(buf, sizeof(buf), "block", p)) {
     376           0 :             av_strlcpy(exclude_sources, buf, sizeof(exclude_sources));
     377           0 :             rtp_parse_addr_list(h, buf, &s->ssm_exclude_addrs, &s->nb_ssm_exclude_addrs);
     378             :         } else {
     379           0 :             rtp_parse_addr_list(h, s->block, &s->ssm_exclude_addrs, &s->nb_ssm_exclude_addrs);
     380           0 :             block = s->block;
     381             :         }
     382             :     }
     383             : 
     384           0 :     if (s->fec_options_str) {
     385           0 :         p = s->fec_options_str;
     386             : 
     387           0 :         if (!(fec_protocol = av_get_token(&p, "="))) {
     388           0 :             av_log(h, AV_LOG_ERROR, "Failed to parse the FEC protocol value\n");
     389           0 :             goto fail;
     390             :         }
     391           0 :         if (strcmp(fec_protocol, "prompeg")) {
     392           0 :             av_log(h, AV_LOG_ERROR, "Unsupported FEC protocol %s\n", fec_protocol);
     393           0 :             goto fail;
     394             :         }
     395             : 
     396           0 :         p = s->fec_options_str + strlen(fec_protocol);
     397           0 :         while (*p && *p == '=') p++;
     398             : 
     399           0 :         if (av_dict_parse_string(&fec_opts, p, "=", ":", 0) < 0) {
     400           0 :             av_log(h, AV_LOG_ERROR, "Failed to parse the FEC options\n");
     401           0 :             goto fail;
     402             :         }
     403           0 :         if (s->ttl > 0) {
     404           0 :             snprintf(buf, sizeof (buf), "%d", s->ttl);
     405           0 :             av_dict_set(&fec_opts, "ttl", buf, 0);
     406             :         }
     407             :     }
     408             : 
     409           0 :     for (i = 0; i < max_retry_count; i++) {
     410           0 :         build_udp_url(s, buf, sizeof(buf),
     411             :                       hostname, rtp_port, s->local_rtpport,
     412             :                       sources, block);
     413           0 :         if (ffurl_open_whitelist(&s->rtp_hd, buf, flags, &h->interrupt_callback,
     414             :                                  NULL, h->protocol_whitelist, h->protocol_blacklist, h) < 0)
     415           0 :             goto fail;
     416           0 :         s->local_rtpport = ff_udp_get_local_port(s->rtp_hd);
     417           0 :         if(s->local_rtpport == 65535) {
     418           0 :             s->local_rtpport = -1;
     419           0 :             continue;
     420             :         }
     421           0 :         rtcpflags = flags | AVIO_FLAG_WRITE;
     422           0 :         if (s->local_rtcpport < 0) {
     423           0 :             s->local_rtcpport = s->local_rtpport + 1;
     424           0 :             build_udp_url(s, buf, sizeof(buf),
     425             :                           hostname, s->rtcp_port, s->local_rtcpport,
     426             :                           sources, block);
     427           0 :             if (ffurl_open_whitelist(&s->rtcp_hd, buf, rtcpflags,
     428           0 :                                      &h->interrupt_callback, NULL,
     429             :                                      h->protocol_whitelist, h->protocol_blacklist, h) < 0) {
     430           0 :                 s->local_rtpport = s->local_rtcpport = -1;
     431           0 :                 continue;
     432             :             }
     433           0 :             break;
     434             :         }
     435           0 :         build_udp_url(s, buf, sizeof(buf),
     436             :                       hostname, s->rtcp_port, s->local_rtcpport,
     437             :                       sources, block);
     438           0 :         if (ffurl_open_whitelist(&s->rtcp_hd, buf, rtcpflags, &h->interrupt_callback,
     439             :                                  NULL, h->protocol_whitelist, h->protocol_blacklist, h) < 0)
     440           0 :             goto fail;
     441           0 :         break;
     442             :     }
     443             : 
     444           0 :     s->fec_hd = NULL;
     445           0 :     if (fec_protocol) {
     446           0 :         ff_url_join(buf, sizeof(buf), fec_protocol, NULL, hostname, rtp_port, NULL);
     447           0 :         if (ffurl_open_whitelist(&s->fec_hd, buf, flags, &h->interrupt_callback,
     448             :                              &fec_opts, h->protocol_whitelist, h->protocol_blacklist, h) < 0)
     449           0 :             goto fail;
     450             :     }
     451             : 
     452             :     /* just to ease handle access. XXX: need to suppress direct handle
     453             :        access */
     454           0 :     s->rtp_fd = ffurl_get_file_handle(s->rtp_hd);
     455           0 :     s->rtcp_fd = ffurl_get_file_handle(s->rtcp_hd);
     456             : 
     457           0 :     h->max_packet_size = s->rtp_hd->max_packet_size;
     458           0 :     h->is_streamed = 1;
     459             : 
     460           0 :     av_free(fec_protocol);
     461           0 :     av_dict_free(&fec_opts);
     462             : 
     463           0 :     return 0;
     464             : 
     465           0 :  fail:
     466           0 :     if (s->rtp_hd)
     467           0 :         ffurl_close(s->rtp_hd);
     468           0 :     if (s->rtcp_hd)
     469           0 :         ffurl_close(s->rtcp_hd);
     470           0 :     ffurl_closep(&s->fec_hd);
     471           0 :     av_free(fec_protocol);
     472           0 :     av_dict_free(&fec_opts);
     473           0 :     return AVERROR(EIO);
     474             : }
     475             : 
     476           0 : static int rtp_read(URLContext *h, uint8_t *buf, int size)
     477             : {
     478           0 :     RTPContext *s = h->priv_data;
     479             :     int len, n, i;
     480           0 :     struct pollfd p[2] = {{s->rtp_fd, POLLIN, 0}, {s->rtcp_fd, POLLIN, 0}};
     481           0 :     int poll_delay = h->flags & AVIO_FLAG_NONBLOCK ? 0 : 100;
     482           0 :     struct sockaddr_storage *addrs[2] = { &s->last_rtp_source, &s->last_rtcp_source };
     483           0 :     socklen_t *addr_lens[2] = { &s->last_rtp_source_len, &s->last_rtcp_source_len };
     484             : 
     485             :     for(;;) {
     486           0 :         if (ff_check_interrupt(&h->interrupt_callback))
     487           0 :             return AVERROR_EXIT;
     488           0 :         n = poll(p, 2, poll_delay);
     489           0 :         if (n > 0) {
     490             :             /* first try RTCP, then RTP */
     491           0 :             for (i = 1; i >= 0; i--) {
     492           0 :                 if (!(p[i].revents & POLLIN))
     493           0 :                     continue;
     494           0 :                 *addr_lens[i] = sizeof(*addrs[i]);
     495           0 :                 len = recvfrom(p[i].fd, buf, size, 0,
     496           0 :                                 (struct sockaddr *)addrs[i], addr_lens[i]);
     497           0 :                 if (len < 0) {
     498           0 :                     if (ff_neterrno() == AVERROR(EAGAIN) ||
     499           0 :                         ff_neterrno() == AVERROR(EINTR))
     500           0 :                         continue;
     501           0 :                     return AVERROR(EIO);
     502             :                 }
     503           0 :                 if (rtp_check_source_lists(s, addrs[i]))
     504           0 :                     continue;
     505           0 :                 return len;
     506             :             }
     507           0 :         } else if (n < 0) {
     508           0 :             if (ff_neterrno() == AVERROR(EINTR))
     509           0 :                 continue;
     510           0 :             return AVERROR(EIO);
     511             :         }
     512           0 :         if (h->flags & AVIO_FLAG_NONBLOCK)
     513           0 :             return AVERROR(EAGAIN);
     514             :     }
     515             : }
     516             : 
     517           0 : static int rtp_write(URLContext *h, const uint8_t *buf, int size)
     518             : {
     519           0 :     RTPContext *s = h->priv_data;
     520             :     int ret, ret_fec;
     521             :     URLContext *hd;
     522             : 
     523           0 :     if (size < 2)
     524           0 :         return AVERROR(EINVAL);
     525             : 
     526           0 :     if ((buf[0] & 0xc0) != (RTP_VERSION << 6))
     527           0 :         av_log(h, AV_LOG_WARNING, "Data doesn't look like RTP packets, "
     528             :                                   "make sure the RTP muxer is used\n");
     529             : 
     530           0 :     if (s->write_to_source) {
     531             :         int fd;
     532             :         struct sockaddr_storage *source, temp_source;
     533             :         socklen_t *source_len, temp_len;
     534           0 :         if (!s->last_rtp_source.ss_family && !s->last_rtcp_source.ss_family) {
     535           0 :             av_log(h, AV_LOG_ERROR,
     536             :                    "Unable to send packet to source, no packets received yet\n");
     537             :             // Intentionally not returning an error here
     538           0 :             return size;
     539             :         }
     540             : 
     541           0 :         if (RTP_PT_IS_RTCP(buf[1])) {
     542           0 :             fd = s->rtcp_fd;
     543           0 :             source     = &s->last_rtcp_source;
     544           0 :             source_len = &s->last_rtcp_source_len;
     545             :         } else {
     546           0 :             fd = s->rtp_fd;
     547           0 :             source     = &s->last_rtp_source;
     548           0 :             source_len = &s->last_rtp_source_len;
     549             :         }
     550           0 :         if (!source->ss_family) {
     551           0 :             source      = &temp_source;
     552           0 :             source_len  = &temp_len;
     553           0 :             if (RTP_PT_IS_RTCP(buf[1])) {
     554           0 :                 temp_source = s->last_rtp_source;
     555           0 :                 temp_len    = s->last_rtp_source_len;
     556           0 :                 set_port(source, get_port(source) + 1);
     557           0 :                 av_log(h, AV_LOG_INFO,
     558             :                        "Not received any RTCP packets yet, inferring peer port "
     559             :                        "from the RTP port\n");
     560             :             } else {
     561           0 :                 temp_source = s->last_rtcp_source;
     562           0 :                 temp_len    = s->last_rtcp_source_len;
     563           0 :                 set_port(source, get_port(source) - 1);
     564           0 :                 av_log(h, AV_LOG_INFO,
     565             :                        "Not received any RTP packets yet, inferring peer port "
     566             :                        "from the RTCP port\n");
     567             :             }
     568             :         }
     569             : 
     570           0 :         if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
     571           0 :             ret = ff_network_wait_fd(fd, 1);
     572           0 :             if (ret < 0)
     573           0 :                 return ret;
     574             :         }
     575           0 :         ret = sendto(fd, buf, size, 0, (struct sockaddr *) source,
     576             :                      *source_len);
     577             : 
     578           0 :         return ret < 0 ? ff_neterrno() : ret;
     579             :     }
     580             : 
     581           0 :     if (RTP_PT_IS_RTCP(buf[1])) {
     582             :         /* RTCP payload type */
     583           0 :         hd = s->rtcp_hd;
     584             :     } else {
     585             :         /* RTP payload type */
     586           0 :         hd = s->rtp_hd;
     587             :     }
     588             : 
     589           0 :     if ((ret = ffurl_write(hd, buf, size)) < 0) {
     590           0 :         return ret;
     591             :     }
     592             : 
     593           0 :     if (s->fec_hd && !RTP_PT_IS_RTCP(buf[1])) {
     594           0 :         if ((ret_fec = ffurl_write(s->fec_hd, buf, size)) < 0) {
     595           0 :             av_log(h, AV_LOG_ERROR, "Failed to send FEC\n");
     596           0 :             return ret_fec;
     597             :         }
     598             :     }
     599             : 
     600           0 :     return ret;
     601             : }
     602             : 
     603           0 : static int rtp_close(URLContext *h)
     604             : {
     605           0 :     RTPContext *s = h->priv_data;
     606             :     int i;
     607             : 
     608           0 :     for (i = 0; i < s->nb_ssm_include_addrs; i++)
     609           0 :         av_freep(&s->ssm_include_addrs[i]);
     610           0 :     av_freep(&s->ssm_include_addrs);
     611           0 :     for (i = 0; i < s->nb_ssm_exclude_addrs; i++)
     612           0 :         av_freep(&s->ssm_exclude_addrs[i]);
     613           0 :     av_freep(&s->ssm_exclude_addrs);
     614             : 
     615           0 :     ffurl_close(s->rtp_hd);
     616           0 :     ffurl_close(s->rtcp_hd);
     617           0 :     ffurl_closep(&s->fec_hd);
     618           0 :     return 0;
     619             : }
     620             : 
     621             : /**
     622             :  * Return the local rtp port used by the RTP connection
     623             :  * @param h media file context
     624             :  * @return the local port number
     625             :  */
     626             : 
     627           0 : int ff_rtp_get_local_rtp_port(URLContext *h)
     628             : {
     629           0 :     RTPContext *s = h->priv_data;
     630           0 :     return ff_udp_get_local_port(s->rtp_hd);
     631             : }
     632             : 
     633             : /**
     634             :  * Return the local rtcp port used by the RTP connection
     635             :  * @param h media file context
     636             :  * @return the local port number
     637             :  */
     638             : 
     639           0 : int ff_rtp_get_local_rtcp_port(URLContext *h)
     640             : {
     641           0 :     RTPContext *s = h->priv_data;
     642           0 :     return ff_udp_get_local_port(s->rtcp_hd);
     643             : }
     644             : 
     645           0 : static int rtp_get_file_handle(URLContext *h)
     646             : {
     647           0 :     RTPContext *s = h->priv_data;
     648           0 :     return s->rtp_fd;
     649             : }
     650             : 
     651           0 : static int rtp_get_multi_file_handle(URLContext *h, int **handles,
     652             :                                      int *numhandles)
     653             : {
     654           0 :     RTPContext *s = h->priv_data;
     655           0 :     int *hs       = *handles = av_malloc(sizeof(**handles) * 2);
     656           0 :     if (!hs)
     657           0 :         return AVERROR(ENOMEM);
     658           0 :     hs[0] = s->rtp_fd;
     659           0 :     hs[1] = s->rtcp_fd;
     660           0 :     *numhandles = 2;
     661           0 :     return 0;
     662             : }
     663             : 
     664             : const URLProtocol ff_rtp_protocol = {
     665             :     .name                      = "rtp",
     666             :     .url_open                  = rtp_open,
     667             :     .url_read                  = rtp_read,
     668             :     .url_write                 = rtp_write,
     669             :     .url_close                 = rtp_close,
     670             :     .url_get_file_handle       = rtp_get_file_handle,
     671             :     .url_get_multi_file_handle = rtp_get_multi_file_handle,
     672             :     .priv_data_size            = sizeof(RTPContext),
     673             :     .flags                     = URL_PROTOCOL_FLAG_NETWORK,
     674             :     .priv_data_class           = &rtp_class,
     675             : };

Generated by: LCOV version 1.13