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
,
195 const char *include_sources
,
196 const char *exclude_sources
)
198 ff_url_join(buf
, buf_size
, "udp", NULL
, hostname
, port
, NULL
);
200 url_add_option(buf
, buf_size
, "localport=%d", local_port
);
202 url_add_option(buf
, buf_size
, "ttl=%d", ttl
);
203 if (max_packet_size
>=0)
204 url_add_option(buf
, buf_size
, "pkt_size=%d", max_packet_size
);
206 url_add_option(buf
, buf_size
, "connect=1");
207 url_add_option(buf
, buf_size
, "fifo_size=0");
208 if (include_sources
&& include_sources
[0])
209 url_add_option(buf
, buf_size
, "sources=%s", include_sources
);
210 if (exclude_sources
&& exclude_sources
[0])
211 url_add_option(buf
, buf_size
, "block=%s", exclude_sources
);
214 static void rtp_parse_addr_list(URLContext
*h
, char *buf
,
215 struct sockaddr_storage
***address_list_ptr
,
216 int *address_list_size_ptr
)
218 struct addrinfo
*ai
= NULL
;
219 struct sockaddr_storage
*source_addr
;
220 char tmp
= '\0', *p
= buf
, *next
;
222 /* Resolve all of the IPs */
225 next
= strchr(p
, ',');
232 ai
= rtp_resolve_host(p
, 0, SOCK_DGRAM
, AF_UNSPEC
, 0);
234 source_addr
= av_mallocz(sizeof(struct sockaddr_storage
));
238 memcpy(source_addr
, ai
->ai_addr
, ai
->ai_addrlen
);
240 dynarray_add(address_list_ptr
, address_list_size_ptr
, source_addr
);
242 av_log(h
, AV_LOG_WARNING
, "Unable to resolve %s\n", p
);
255 * url syntax: rtp://host:port[?option=val...]
256 * option: 'ttl=n' : set the ttl value (for multicast only)
257 * 'rtcpport=n' : set the remote rtcp port to n
258 * 'localrtpport=n' : set the local rtp port to n
259 * 'localrtcpport=n' : set the local rtcp port to n
260 * 'pkt_size=n' : set max packet size
261 * 'connect=0/1' : do a connect() on the UDP socket
262 * 'sources=ip[,ip]' : list allowed source IP addresses
263 * 'block=ip[,ip]' : list disallowed source IP addresses
264 * 'write_to_source=0/1' : send packets to the source address of the latest received packet
266 * 'localport=n' : set the local port to n
268 * if rtcpport isn't set the rtcp port will be the rtp port + 1
269 * if local rtp port isn't set any available port will be used for the local
271 * if the local rtcp port is not set it will be the local rtp port + 1
274 static int rtp_open(URLContext
*h
, const char *uri
, int flags
)
276 RTPContext
*s
= h
->priv_data
;
277 int rtp_port
, rtcp_port
,
279 local_rtp_port
, local_rtcp_port
, max_packet_size
;
280 char hostname
[256], include_sources
[1024] = "", exclude_sources
[1024] = "";
284 int i
, max_retry_count
= 3;
286 av_url_split(NULL
, 0, NULL
, 0, hostname
, sizeof(hostname
), &rtp_port
,
287 path
, sizeof(path
), uri
);
288 /* extract parameters */
290 rtcp_port
= rtp_port
+1;
292 local_rtcp_port
= -1;
293 max_packet_size
= -1;
296 p
= strchr(uri
, '?');
298 if (av_find_info_tag(buf
, sizeof(buf
), "ttl", p
)) {
299 ttl
= strtol(buf
, NULL
, 10);
301 if (av_find_info_tag(buf
, sizeof(buf
), "rtcpport", p
)) {
302 rtcp_port
= strtol(buf
, NULL
, 10);
304 if (av_find_info_tag(buf
, sizeof(buf
), "localport", p
)) {
305 local_rtp_port
= strtol(buf
, NULL
, 10);
307 if (av_find_info_tag(buf
, sizeof(buf
), "localrtpport", p
)) {
308 local_rtp_port
= strtol(buf
, NULL
, 10);
310 if (av_find_info_tag(buf
, sizeof(buf
), "localrtcpport", p
)) {
311 local_rtcp_port
= strtol(buf
, NULL
, 10);
313 if (av_find_info_tag(buf
, sizeof(buf
), "pkt_size", p
)) {
314 max_packet_size
= strtol(buf
, NULL
, 10);
316 if (av_find_info_tag(buf
, sizeof(buf
), "connect", p
)) {
317 connect
= strtol(buf
, NULL
, 10);
319 if (av_find_info_tag(buf
, sizeof(buf
), "write_to_source", p
)) {
320 s
->write_to_source
= strtol(buf
, NULL
, 10);
322 if (av_find_info_tag(buf
, sizeof(buf
), "sources", p
)) {
323 av_strlcpy(include_sources
, buf
, sizeof(include_sources
));
324 rtp_parse_addr_list(h
, buf
, &s
->ssm_include_addrs
, &s
->nb_ssm_include_addrs
);
326 if (av_find_info_tag(buf
, sizeof(buf
), "block", p
)) {
327 av_strlcpy(exclude_sources
, buf
, sizeof(exclude_sources
));
328 rtp_parse_addr_list(h
, buf
, &s
->ssm_exclude_addrs
, &s
->nb_ssm_exclude_addrs
);
332 for (i
= 0;i
< max_retry_count
;i
++) {
333 build_udp_url(buf
, sizeof(buf
),
334 hostname
, rtp_port
, local_rtp_port
, ttl
, max_packet_size
,
335 connect
, include_sources
, exclude_sources
);
336 if (ffurl_open(&s
->rtp_hd
, buf
, flags
, &h
->interrupt_callback
, NULL
) < 0)
338 local_rtp_port
= ff_udp_get_local_port(s
->rtp_hd
);
339 if(local_rtp_port
== 65535) {
343 if (local_rtcp_port
<0) {
344 local_rtcp_port
= local_rtp_port
+ 1;
345 build_udp_url(buf
, sizeof(buf
),
346 hostname
, rtcp_port
, local_rtcp_port
, ttl
, max_packet_size
,
347 connect
, include_sources
, exclude_sources
);
348 if (ffurl_open(&s
->rtcp_hd
, buf
, flags
, &h
->interrupt_callback
, NULL
) < 0) {
349 local_rtp_port
= local_rtcp_port
= -1;
354 build_udp_url(buf
, sizeof(buf
),
355 hostname
, rtcp_port
, local_rtcp_port
, ttl
, max_packet_size
,
356 connect
, include_sources
, exclude_sources
);
357 if (ffurl_open(&s
->rtcp_hd
, buf
, flags
, &h
->interrupt_callback
, NULL
) < 0)
362 /* just to ease handle access. XXX: need to suppress direct handle
364 s
->rtp_fd
= ffurl_get_file_handle(s
->rtp_hd
);
365 s
->rtcp_fd
= ffurl_get_file_handle(s
->rtcp_hd
);
367 h
->max_packet_size
= s
->rtp_hd
->max_packet_size
;
373 ffurl_close(s
->rtp_hd
);
375 ffurl_close(s
->rtcp_hd
);
379 static int rtp_read(URLContext
*h
, uint8_t *buf
, int size
)
381 RTPContext
*s
= h
->priv_data
;
383 struct pollfd p
[2] = {{s
->rtp_fd
, POLLIN
, 0}, {s
->rtcp_fd
, POLLIN
, 0}};
384 int poll_delay
= h
->flags
& AVIO_FLAG_NONBLOCK
? 0 : 100;
385 struct sockaddr_storage
*addrs
[2] = { &s
->last_rtp_source
, &s
->last_rtcp_source
};
386 socklen_t
*addr_lens
[2] = { &s
->last_rtp_source_len
, &s
->last_rtcp_source_len
};
389 if (ff_check_interrupt(&h
->interrupt_callback
))
391 n
= poll(p
, 2, poll_delay
);
393 /* first try RTCP, then RTP */
394 for (i
= 1; i
>= 0; i
--) {
395 if (!(p
[i
].revents
& POLLIN
))
397 *addr_lens
[i
] = sizeof(*addrs
[i
]);
398 len
= recvfrom(p
[i
].fd
, buf
, size
, 0,
399 (struct sockaddr
*)addrs
[i
], addr_lens
[i
]);
401 if (ff_neterrno() == AVERROR(EAGAIN
) ||
402 ff_neterrno() == AVERROR(EINTR
))
406 if (rtp_check_source_lists(s
, addrs
[i
]))
411 if (ff_neterrno() == AVERROR(EINTR
))
415 if (h
->flags
& AVIO_FLAG_NONBLOCK
)
416 return AVERROR(EAGAIN
);
421 static int rtp_write(URLContext
*h
, const uint8_t *buf
, int size
)
423 RTPContext
*s
= h
->priv_data
;
428 return AVERROR(EINVAL
);
430 if (s
->write_to_source
) {
432 struct sockaddr_storage
*source
, temp_source
;
433 socklen_t
*source_len
, temp_len
;
434 if (!s
->last_rtp_source
.ss_family
&& !s
->last_rtcp_source
.ss_family
) {
435 av_log(h
, AV_LOG_ERROR
,
436 "Unable to send packet to source, no packets received yet\n");
437 // Intentionally not returning an error here
441 if (RTP_PT_IS_RTCP(buf
[1])) {
443 source
= &s
->last_rtcp_source
;
444 source_len
= &s
->last_rtcp_source_len
;
447 source
= &s
->last_rtp_source
;
448 source_len
= &s
->last_rtp_source_len
;
450 if (!source
->ss_family
) {
451 source
= &temp_source
;
452 source_len
= &temp_len
;
453 if (RTP_PT_IS_RTCP(buf
[1])) {
454 temp_source
= s
->last_rtp_source
;
455 temp_len
= s
->last_rtp_source_len
;
456 set_port(source
, get_port(source
) + 1);
457 av_log(h
, AV_LOG_INFO
,
458 "Not received any RTCP packets yet, inferring peer port "
459 "from the RTP port\n");
461 temp_source
= s
->last_rtcp_source
;
462 temp_len
= s
->last_rtcp_source_len
;
463 set_port(source
, get_port(source
) - 1);
464 av_log(h
, AV_LOG_INFO
,
465 "Not received any RTP packets yet, inferring peer port "
466 "from the RTCP port\n");
470 if (!(h
->flags
& AVIO_FLAG_NONBLOCK
)) {
471 ret
= ff_network_wait_fd(fd
, 1);
475 ret
= sendto(fd
, buf
, size
, 0, (struct sockaddr
*) source
,
478 return ret
< 0 ? ff_neterrno() : ret
;
481 if (RTP_PT_IS_RTCP(buf
[1])) {
482 /* RTCP payload type */
485 /* RTP payload type */
489 ret
= ffurl_write(hd
, buf
, size
);
493 static int rtp_close(URLContext
*h
)
495 RTPContext
*s
= h
->priv_data
;
498 for (i
= 0; i
< s
->nb_ssm_include_addrs
; i
++)
499 av_free(s
->ssm_include_addrs
[i
]);
500 av_freep(&s
->ssm_include_addrs
);
501 for (i
= 0; i
< s
->nb_ssm_exclude_addrs
; i
++)
502 av_free(s
->ssm_exclude_addrs
[i
]);
503 av_freep(&s
->ssm_exclude_addrs
);
505 ffurl_close(s
->rtp_hd
);
506 ffurl_close(s
->rtcp_hd
);
511 * Return the local rtp port used by the RTP connection
512 * @param h media file context
513 * @return the local port number
516 int ff_rtp_get_local_rtp_port(URLContext
*h
)
518 RTPContext
*s
= h
->priv_data
;
519 return ff_udp_get_local_port(s
->rtp_hd
);
523 * Return the local rtcp port used by the RTP connection
524 * @param h media file context
525 * @return the local port number
528 int ff_rtp_get_local_rtcp_port(URLContext
*h
)
530 RTPContext
*s
= h
->priv_data
;
531 return ff_udp_get_local_port(s
->rtcp_hd
);
534 static int rtp_get_file_handle(URLContext
*h
)
536 RTPContext
*s
= h
->priv_data
;
540 static int rtp_get_multi_file_handle(URLContext
*h
, int **handles
,
543 RTPContext
*s
= h
->priv_data
;
544 int *hs
= *handles
= av_malloc(sizeof(**handles
) * 2);
546 return AVERROR(ENOMEM
);
553 URLProtocol ff_rtp_protocol
= {
555 .url_open
= rtp_open
,
556 .url_read
= rtp_read
,
557 .url_write
= rtp_write
,
558 .url_close
= rtp_close
,
559 .url_get_file_handle
= rtp_get_file_handle
,
560 .url_get_multi_file_handle
= rtp_get_multi_file_handle
,
561 .priv_data_size
= sizeof(RTPContext
),
562 .flags
= URL_PROTOCOL_FLAG_NETWORK
,