3 * Copyright (c) 2002 Fabrice Bellard
5 * This file is part of FFmpeg.
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.
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.
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
27 #include "libavutil/parseutils.h"
28 #include "libavutil/avstring.h"
30 #include "avio_internal.h"
38 #include "os_support.h"
44 typedef struct RTPContext
{
45 URLContext
*rtp_hd
, *rtcp_hd
;
46 int rtp_fd
, rtcp_fd
, nb_ssm_include_addrs
, nb_ssm_exclude_addrs
;
47 struct sockaddr_storage
**ssm_include_addrs
, **ssm_exclude_addrs
;
49 struct sockaddr_storage last_rtp_source
, last_rtcp_source
;
50 socklen_t last_rtp_source_len
, last_rtcp_source_len
;
54 * If no filename is given to av_open_input_file because you want to
55 * get the local port first, then you must call this function to set
56 * the remote server address.
58 * @param h media file context
59 * @param uri of the remote server
60 * @return zero if no error.
63 int ff_rtp_set_remote_url(URLContext
*h
, const char *uri
)
65 RTPContext
*s
= h
->priv_data
;
73 av_url_split(NULL
, 0, NULL
, 0, hostname
, sizeof(hostname
), &port
,
74 path
, sizeof(path
), uri
);
79 if (av_find_info_tag(buf
, sizeof(buf
), "rtcpport", p
)) {
80 rtcp_port
= strtol(buf
, NULL
, 10);
84 ff_url_join(buf
, sizeof(buf
), "udp", NULL
, hostname
, port
, "%s", path
);
85 ff_udp_set_remote_url(s
->rtp_hd
, buf
);
87 ff_url_join(buf
, sizeof(buf
), "udp", NULL
, hostname
, rtcp_port
, "%s", path
);
88 ff_udp_set_remote_url(s
->rtcp_hd
, buf
);
92 static struct addrinfo
* rtp_resolve_host(const char *hostname
, int port
,
93 int type
, int family
, int flags
)
95 struct addrinfo hints
= { 0 }, *res
= 0;
99 snprintf(service
, sizeof(service
), "%d", port
);
100 hints
.ai_socktype
= type
;
101 hints
.ai_family
= family
;
102 hints
.ai_flags
= flags
;
103 if ((error
= getaddrinfo(hostname
, service
, &hints
, &res
))) {
105 av_log(NULL
, AV_LOG_ERROR
, "rtp_resolve_host: %s\n", gai_strerror(error
));
111 static int compare_addr(const struct sockaddr_storage
*a
,
112 const struct sockaddr_storage
*b
)
114 if (a
->ss_family
!= b
->ss_family
)
116 if (a
->ss_family
== AF_INET
) {
117 return (((const struct sockaddr_in
*)a
)->sin_addr
.s_addr
!=
118 ((const struct sockaddr_in
*)b
)->sin_addr
.s_addr
);
121 #if HAVE_STRUCT_SOCKADDR_IN6
122 if (a
->ss_family
== AF_INET6
) {
123 const uint8_t *s6_addr_a
= ((const struct sockaddr_in6
*)a
)->sin6_addr
.s6_addr
;
124 const uint8_t *s6_addr_b
= ((const struct sockaddr_in6
*)b
)->sin6_addr
.s6_addr
;
125 return memcmp(s6_addr_a
, s6_addr_b
, 16);
131 static int get_port(const struct sockaddr_storage
*ss
)
133 if (ss
->ss_family
== AF_INET
)
134 return ntohs(((const struct sockaddr_in
*)ss
)->sin_port
);
135 #if HAVE_STRUCT_SOCKADDR_IN6
136 if (ss
->ss_family
== AF_INET6
)
137 return ntohs(((const struct sockaddr_in6
*)ss
)->sin6_port
);
142 static void set_port(struct sockaddr_storage
*ss
, int port
)
144 if (ss
->ss_family
== AF_INET
)
145 ((struct sockaddr_in
*)ss
)->sin_port
= htons(port
);
146 #if HAVE_STRUCT_SOCKADDR_IN6
147 else if (ss
->ss_family
== AF_INET6
)
148 ((struct sockaddr_in6
*)ss
)->sin6_port
= htons(port
);
152 static int rtp_check_source_lists(RTPContext
*s
, struct sockaddr_storage
*source_addr_ptr
)
155 if (s
->nb_ssm_exclude_addrs
) {
156 for (i
= 0; i
< s
->nb_ssm_exclude_addrs
; i
++) {
157 if (!compare_addr(source_addr_ptr
, s
->ssm_exclude_addrs
[i
]))
161 if (s
->nb_ssm_include_addrs
) {
162 for (i
= 0; i
< s
->nb_ssm_include_addrs
; i
++) {
163 if (!compare_addr(source_addr_ptr
, s
->ssm_include_addrs
[i
]))
172 * add option to url of the form:
173 * "http://host:port/path?option1=val1&option2=val2...
176 static av_printf_format(3, 4) void url_add_option(char *buf
, int buf_size
, const char *fmt
, ...)
182 if (strchr(buf
, '?'))
183 av_strlcat(buf
, "&", buf_size
);
185 av_strlcat(buf
, "?", buf_size
);
186 vsnprintf(buf1
, sizeof(buf1
), fmt
, ap
);
187 av_strlcat(buf
, buf1
, buf_size
);
191 static void build_udp_url(char *buf
, int buf_size
,
192 const char *hostname
, int port
,
193 int local_port
, int ttl
,
194 int max_packet_size
, int connect
,
196 const char *include_sources
,
197 const char *exclude_sources
)
199 ff_url_join(buf
, buf_size
, "udp", NULL
, hostname
, port
, NULL
);
201 url_add_option(buf
, buf_size
, "localport=%d", local_port
);
203 url_add_option(buf
, buf_size
, "ttl=%d", ttl
);
204 if (max_packet_size
>=0)
205 url_add_option(buf
, buf_size
, "pkt_size=%d", max_packet_size
);
207 url_add_option(buf
, buf_size
, "connect=1");
209 url_add_option(buf
, buf_size
, "dscp=%d", dscp
);
210 url_add_option(buf
, buf_size
, "fifo_size=0");
211 if (include_sources
&& include_sources
[0])
212 url_add_option(buf
, buf_size
, "sources=%s", include_sources
);
213 if (exclude_sources
&& exclude_sources
[0])
214 url_add_option(buf
, buf_size
, "block=%s", exclude_sources
);
217 static void rtp_parse_addr_list(URLContext
*h
, char *buf
,
218 struct sockaddr_storage
***address_list_ptr
,
219 int *address_list_size_ptr
)
221 struct addrinfo
*ai
= NULL
;
222 struct sockaddr_storage
*source_addr
;
223 char tmp
= '\0', *p
= buf
, *next
;
225 /* Resolve all of the IPs */
228 next
= strchr(p
, ',');
235 ai
= rtp_resolve_host(p
, 0, SOCK_DGRAM
, AF_UNSPEC
, 0);
237 source_addr
= av_mallocz(sizeof(struct sockaddr_storage
));
243 memcpy(source_addr
, ai
->ai_addr
, ai
->ai_addrlen
);
245 dynarray_add(address_list_ptr
, address_list_size_ptr
, source_addr
);
247 av_log(h
, AV_LOG_WARNING
, "Unable to resolve %s\n", p
);
260 * url syntax: rtp://host:port[?option=val...]
261 * option: 'ttl=n' : set the ttl value (for multicast only)
262 * 'rtcpport=n' : set the remote rtcp port to n
263 * 'localrtpport=n' : set the local rtp port to n
264 * 'localrtcpport=n' : set the local rtcp port to n
265 * 'pkt_size=n' : set max packet size
266 * 'connect=0/1' : do a connect() on the UDP socket
267 * 'sources=ip[,ip]' : list allowed source IP addresses
268 * 'block=ip[,ip]' : list disallowed source IP addresses
269 * 'write_to_source=0/1' : send packets to the source address of the latest received packet
270 * 'dscp=n' : set DSCP value to n (QoS)
272 * 'localport=n' : set the local port to n
274 * if rtcpport isn't set the rtcp port will be the rtp port + 1
275 * if local rtp port isn't set any available port will be used for the local
277 * if the local rtcp port is not set it will be the local rtp port + 1
280 static int rtp_open(URLContext
*h
, const char *uri
, int flags
)
282 RTPContext
*s
= h
->priv_data
;
283 int rtp_port
, rtcp_port
,
285 local_rtp_port
, local_rtcp_port
, max_packet_size
, dscp
;
286 char hostname
[256], include_sources
[1024] = "", exclude_sources
[1024] = "";
290 int i
, max_retry_count
= 3;
292 av_url_split(NULL
, 0, NULL
, 0, hostname
, sizeof(hostname
), &rtp_port
,
293 path
, sizeof(path
), uri
);
294 /* extract parameters */
296 rtcp_port
= rtp_port
+1;
298 local_rtcp_port
= -1;
299 max_packet_size
= -1;
303 p
= strchr(uri
, '?');
305 if (av_find_info_tag(buf
, sizeof(buf
), "ttl", p
)) {
306 ttl
= strtol(buf
, NULL
, 10);
308 if (av_find_info_tag(buf
, sizeof(buf
), "rtcpport", p
)) {
309 rtcp_port
= strtol(buf
, NULL
, 10);
311 if (av_find_info_tag(buf
, sizeof(buf
), "localport", p
)) {
312 local_rtp_port
= strtol(buf
, NULL
, 10);
314 if (av_find_info_tag(buf
, sizeof(buf
), "localrtpport", p
)) {
315 local_rtp_port
= strtol(buf
, NULL
, 10);
317 if (av_find_info_tag(buf
, sizeof(buf
), "localrtcpport", p
)) {
318 local_rtcp_port
= strtol(buf
, NULL
, 10);
320 if (av_find_info_tag(buf
, sizeof(buf
), "pkt_size", p
)) {
321 max_packet_size
= strtol(buf
, NULL
, 10);
323 if (av_find_info_tag(buf
, sizeof(buf
), "connect", p
)) {
324 connect
= strtol(buf
, NULL
, 10);
326 if (av_find_info_tag(buf
, sizeof(buf
), "write_to_source", p
)) {
327 s
->write_to_source
= strtol(buf
, NULL
, 10);
329 if (av_find_info_tag(buf
, sizeof(buf
), "dscp", p
)) {
330 dscp
= strtol(buf
, NULL
, 10);
332 if (av_find_info_tag(buf
, sizeof(buf
), "sources", p
)) {
333 av_strlcpy(include_sources
, buf
, sizeof(include_sources
));
334 rtp_parse_addr_list(h
, buf
, &s
->ssm_include_addrs
, &s
->nb_ssm_include_addrs
);
336 if (av_find_info_tag(buf
, sizeof(buf
), "block", p
)) {
337 av_strlcpy(exclude_sources
, buf
, sizeof(exclude_sources
));
338 rtp_parse_addr_list(h
, buf
, &s
->ssm_exclude_addrs
, &s
->nb_ssm_exclude_addrs
);
342 for (i
= 0;i
< max_retry_count
;i
++) {
343 build_udp_url(buf
, sizeof(buf
),
344 hostname
, rtp_port
, local_rtp_port
, ttl
, max_packet_size
,
345 connect
, dscp
, include_sources
, exclude_sources
);
346 if (ffurl_open(&s
->rtp_hd
, buf
, flags
, &h
->interrupt_callback
, NULL
) < 0)
348 local_rtp_port
= ff_udp_get_local_port(s
->rtp_hd
);
349 if(local_rtp_port
== 65535) {
353 if (local_rtcp_port
<0) {
354 local_rtcp_port
= local_rtp_port
+ 1;
355 build_udp_url(buf
, sizeof(buf
),
356 hostname
, rtcp_port
, local_rtcp_port
, ttl
, max_packet_size
,
357 connect
, dscp
, include_sources
, exclude_sources
);
358 if (ffurl_open(&s
->rtcp_hd
, buf
, flags
, &h
->interrupt_callback
, NULL
) < 0) {
359 local_rtp_port
= local_rtcp_port
= -1;
364 build_udp_url(buf
, sizeof(buf
),
365 hostname
, rtcp_port
, local_rtcp_port
, ttl
, max_packet_size
,
366 connect
, dscp
, include_sources
, exclude_sources
);
367 if (ffurl_open(&s
->rtcp_hd
, buf
, flags
, &h
->interrupt_callback
, NULL
) < 0)
372 /* just to ease handle access. XXX: need to suppress direct handle
374 s
->rtp_fd
= ffurl_get_file_handle(s
->rtp_hd
);
375 s
->rtcp_fd
= ffurl_get_file_handle(s
->rtcp_hd
);
377 h
->max_packet_size
= s
->rtp_hd
->max_packet_size
;
383 ffurl_close(s
->rtp_hd
);
385 ffurl_close(s
->rtcp_hd
);
389 static int rtp_read(URLContext
*h
, uint8_t *buf
, int size
)
391 RTPContext
*s
= h
->priv_data
;
393 struct pollfd p
[2] = {{s
->rtp_fd
, POLLIN
, 0}, {s
->rtcp_fd
, POLLIN
, 0}};
394 int poll_delay
= h
->flags
& AVIO_FLAG_NONBLOCK
? 0 : 100;
395 struct sockaddr_storage
*addrs
[2] = { &s
->last_rtp_source
, &s
->last_rtcp_source
};
396 socklen_t
*addr_lens
[2] = { &s
->last_rtp_source_len
, &s
->last_rtcp_source_len
};
399 if (ff_check_interrupt(&h
->interrupt_callback
))
401 n
= poll(p
, 2, poll_delay
);
403 /* first try RTCP, then RTP */
404 for (i
= 1; i
>= 0; i
--) {
405 if (!(p
[i
].revents
& POLLIN
))
407 *addr_lens
[i
] = sizeof(*addrs
[i
]);
408 len
= recvfrom(p
[i
].fd
, buf
, size
, 0,
409 (struct sockaddr
*)addrs
[i
], addr_lens
[i
]);
411 if (ff_neterrno() == AVERROR(EAGAIN
) ||
412 ff_neterrno() == AVERROR(EINTR
))
416 if (rtp_check_source_lists(s
, addrs
[i
]))
421 if (ff_neterrno() == AVERROR(EINTR
))
425 if (h
->flags
& AVIO_FLAG_NONBLOCK
)
426 return AVERROR(EAGAIN
);
431 static int rtp_write(URLContext
*h
, const uint8_t *buf
, int size
)
433 RTPContext
*s
= h
->priv_data
;
438 return AVERROR(EINVAL
);
440 if (s
->write_to_source
) {
442 struct sockaddr_storage
*source
, temp_source
;
443 socklen_t
*source_len
, temp_len
;
444 if (!s
->last_rtp_source
.ss_family
&& !s
->last_rtcp_source
.ss_family
) {
445 av_log(h
, AV_LOG_ERROR
,
446 "Unable to send packet to source, no packets received yet\n");
447 // Intentionally not returning an error here
451 if (RTP_PT_IS_RTCP(buf
[1])) {
453 source
= &s
->last_rtcp_source
;
454 source_len
= &s
->last_rtcp_source_len
;
457 source
= &s
->last_rtp_source
;
458 source_len
= &s
->last_rtp_source_len
;
460 if (!source
->ss_family
) {
461 source
= &temp_source
;
462 source_len
= &temp_len
;
463 if (RTP_PT_IS_RTCP(buf
[1])) {
464 temp_source
= s
->last_rtp_source
;
465 temp_len
= s
->last_rtp_source_len
;
466 set_port(source
, get_port(source
) + 1);
467 av_log(h
, AV_LOG_INFO
,
468 "Not received any RTCP packets yet, inferring peer port "
469 "from the RTP port\n");
471 temp_source
= s
->last_rtcp_source
;
472 temp_len
= s
->last_rtcp_source_len
;
473 set_port(source
, get_port(source
) - 1);
474 av_log(h
, AV_LOG_INFO
,
475 "Not received any RTP packets yet, inferring peer port "
476 "from the RTCP port\n");
480 if (!(h
->flags
& AVIO_FLAG_NONBLOCK
)) {
481 ret
= ff_network_wait_fd(fd
, 1);
485 ret
= sendto(fd
, buf
, size
, 0, (struct sockaddr
*) source
,
488 return ret
< 0 ? ff_neterrno() : ret
;
491 if (RTP_PT_IS_RTCP(buf
[1])) {
492 /* RTCP payload type */
495 /* RTP payload type */
499 ret
= ffurl_write(hd
, buf
, size
);
503 static int rtp_close(URLContext
*h
)
505 RTPContext
*s
= h
->priv_data
;
508 for (i
= 0; i
< s
->nb_ssm_include_addrs
; i
++)
509 av_free(s
->ssm_include_addrs
[i
]);
510 av_freep(&s
->ssm_include_addrs
);
511 for (i
= 0; i
< s
->nb_ssm_exclude_addrs
; i
++)
512 av_free(s
->ssm_exclude_addrs
[i
]);
513 av_freep(&s
->ssm_exclude_addrs
);
515 ffurl_close(s
->rtp_hd
);
516 ffurl_close(s
->rtcp_hd
);
521 * Return the local rtp port used by the RTP connection
522 * @param h media file context
523 * @return the local port number
526 int ff_rtp_get_local_rtp_port(URLContext
*h
)
528 RTPContext
*s
= h
->priv_data
;
529 return ff_udp_get_local_port(s
->rtp_hd
);
533 * Return the local rtcp port used by the RTP connection
534 * @param h media file context
535 * @return the local port number
538 int ff_rtp_get_local_rtcp_port(URLContext
*h
)
540 RTPContext
*s
= h
->priv_data
;
541 return ff_udp_get_local_port(s
->rtcp_hd
);
544 static int rtp_get_file_handle(URLContext
*h
)
546 RTPContext
*s
= h
->priv_data
;
550 static int rtp_get_multi_file_handle(URLContext
*h
, int **handles
,
553 RTPContext
*s
= h
->priv_data
;
554 int *hs
= *handles
= av_malloc(sizeof(**handles
) * 2);
556 return AVERROR(ENOMEM
);
563 URLProtocol ff_rtp_protocol
= {
565 .url_open
= rtp_open
,
566 .url_read
= rtp_read
,
567 .url_write
= rtp_write
,
568 .url_close
= rtp_close
,
569 .url_get_file_handle
= rtp_get_file_handle
,
570 .url_get_multi_file_handle
= rtp_get_multi_file_handle
,
571 .priv_data_size
= sizeof(RTPContext
),
572 .flags
= URL_PROTOCOL_FLAG_NETWORK
,