2 * UDP prototype streaming system
3 * Copyright (c) 2000, 2001, 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
23 * @file libavformat/udp.c
27 #define _BSD_SOURCE /* Needed for using struct ip_mreq with recent glibc */
31 #include "os_support.h"
33 #include <sys/select.h>
37 #ifndef IPV6_ADD_MEMBERSHIP
38 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
39 #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
42 #define IN_MULTICAST(a) ((((uint32_t)(a)) & 0xf0000000) == 0xe0000000)
44 #ifndef IN6_IS_ADDR_MULTICAST
45 #define IN6_IS_ADDR_MULTICAST(a) (((uint8_t *) (a))[0] == 0xff)
56 struct sockaddr_in dest_addr
;
58 struct sockaddr_storage dest_addr
;
63 #define UDP_TX_BUF_SIZE 32768
64 #define UDP_MAX_PKT_SIZE 65536
66 static int udp_set_multicast_ttl(int sockfd
, int mcastTTL
, struct sockaddr
*addr
) {
67 #ifdef IP_MULTICAST_TTL
68 if (addr
->sa_family
== AF_INET
) {
69 if (setsockopt(sockfd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &mcastTTL
, sizeof(mcastTTL
)) < 0) {
70 av_log(NULL
, AV_LOG_ERROR
, "setsockopt(IP_MULTICAST_TTL): %s\n", strerror(errno
));
76 if (addr
->sa_family
== AF_INET6
) {
77 if (setsockopt(sockfd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &mcastTTL
, sizeof(mcastTTL
)) < 0) {
78 av_log(NULL
, AV_LOG_ERROR
, "setsockopt(IPV6_MULTICAST_HOPS): %s\n", strerror(errno
));
86 static int udp_join_multicast_group(int sockfd
, struct sockaddr
*addr
) {
87 #ifdef IP_ADD_MEMBERSHIP
88 if (addr
->sa_family
== AF_INET
) {
91 mreq
.imr_multiaddr
.s_addr
= ((struct sockaddr_in
*)addr
)->sin_addr
.s_addr
;
92 mreq
.imr_interface
.s_addr
= INADDR_ANY
;
93 if (setsockopt(sockfd
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (const void *)&mreq
, sizeof(mreq
)) < 0) {
94 av_log(NULL
, AV_LOG_ERROR
, "setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno
));
100 if (addr
->sa_family
== AF_INET6
) {
101 struct ipv6_mreq mreq6
;
103 memcpy(&mreq6
.ipv6mr_multiaddr
, &(((struct sockaddr_in6
*)addr
)->sin6_addr
), sizeof(struct in6_addr
));
104 mreq6
.ipv6mr_interface
= 0;
105 if (setsockopt(sockfd
, IPPROTO_IPV6
, IPV6_ADD_MEMBERSHIP
, &mreq6
, sizeof(mreq6
)) < 0) {
106 av_log(NULL
, AV_LOG_ERROR
, "setsockopt(IPV6_ADD_MEMBERSHIP): %s\n", strerror(errno
));
114 static int udp_leave_multicast_group(int sockfd
, struct sockaddr
*addr
) {
115 #ifdef IP_DROP_MEMBERSHIP
116 if (addr
->sa_family
== AF_INET
) {
119 mreq
.imr_multiaddr
.s_addr
= ((struct sockaddr_in
*)addr
)->sin_addr
.s_addr
;
120 mreq
.imr_interface
.s_addr
= INADDR_ANY
;
121 if (setsockopt(sockfd
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
, (const void *)&mreq
, sizeof(mreq
)) < 0) {
122 av_log(NULL
, AV_LOG_ERROR
, "setsockopt(IP_DROP_MEMBERSHIP): %s\n", strerror(errno
));
128 if (addr
->sa_family
== AF_INET6
) {
129 struct ipv6_mreq mreq6
;
131 memcpy(&mreq6
.ipv6mr_multiaddr
, &(((struct sockaddr_in6
*)addr
)->sin6_addr
), sizeof(struct in6_addr
));
132 mreq6
.ipv6mr_interface
= 0;
133 if (setsockopt(sockfd
, IPPROTO_IPV6
, IPV6_DROP_MEMBERSHIP
, &mreq6
, sizeof(mreq6
)) < 0) {
134 av_log(NULL
, AV_LOG_ERROR
, "setsockopt(IPV6_DROP_MEMBERSHIP): %s\n", strerror(errno
));
143 static struct addrinfo
* udp_ipv6_resolve_host(const char *hostname
, int port
, int type
, int family
, int flags
) {
144 struct addrinfo hints
, *res
= 0;
147 const char *node
= 0, *service
= "0";
150 snprintf(sport
, sizeof(sport
), "%d", port
);
153 if ((hostname
) && (hostname
[0] != '\0') && (hostname
[0] != '?')) {
156 memset(&hints
, 0, sizeof(hints
));
157 hints
.ai_socktype
= type
;
158 hints
.ai_family
= family
;
159 hints
.ai_flags
= flags
;
160 if ((error
= getaddrinfo(node
, service
, &hints
, &res
))) {
161 av_log(NULL
, AV_LOG_ERROR
, "udp_ipv6_resolve_host: %s\n", gai_strerror(error
));
167 static int udp_set_url(struct sockaddr_storage
*addr
, const char *hostname
, int port
) {
168 struct addrinfo
*res0
;
171 res0
= udp_ipv6_resolve_host(hostname
, port
, SOCK_DGRAM
, AF_UNSPEC
, 0);
172 if (res0
== 0) return AVERROR(EIO
);
173 memcpy(addr
, res0
->ai_addr
, res0
->ai_addrlen
);
174 addr_len
= res0
->ai_addrlen
;
180 static int is_multicast_address(struct sockaddr_storage
*addr
)
182 if (addr
->ss_family
== AF_INET
) {
183 return IN_MULTICAST(ntohl(((struct sockaddr_in
*)addr
)->sin_addr
.s_addr
));
185 if (addr
->ss_family
== AF_INET6
) {
186 return IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6
*)addr
)->sin6_addr
);
192 static int udp_socket_create(UDPContext
*s
, struct sockaddr_storage
*addr
, int *addr_len
)
195 struct addrinfo
*res0
= NULL
, *res
= NULL
;
196 int family
= AF_UNSPEC
;
198 if (((struct sockaddr
*) &s
->dest_addr
)->sa_family
)
199 family
= ((struct sockaddr
*) &s
->dest_addr
)->sa_family
;
200 res0
= udp_ipv6_resolve_host(0, s
->local_port
, SOCK_DGRAM
, family
, AI_PASSIVE
);
203 for (res
= res0
; res
; res
=res
->ai_next
) {
204 udp_fd
= socket(res
->ai_family
, SOCK_DGRAM
, 0);
205 if (udp_fd
> 0) break;
206 av_log(NULL
, AV_LOG_ERROR
, "socket: %s\n", strerror(errno
));
212 memcpy(addr
, res
->ai_addr
, res
->ai_addrlen
);
213 *addr_len
= res
->ai_addrlen
;
227 static int udp_port(struct sockaddr_storage
*addr
, int addr_len
)
229 char sbuf
[sizeof(int)*3+1];
231 if (getnameinfo((struct sockaddr
*)addr
, addr_len
, NULL
, 0, sbuf
, sizeof(sbuf
), NI_NUMERICSERV
) != 0) {
232 av_log(NULL
, AV_LOG_ERROR
, "getnameinfo: %s\n", strerror(errno
));
236 return strtol(sbuf
, NULL
, 10);
241 static int udp_set_url(struct sockaddr_in
*addr
, const char *hostname
, int port
)
243 /* set the destination address */
244 if (resolve_host(&addr
->sin_addr
, hostname
) < 0)
246 addr
->sin_family
= AF_INET
;
247 addr
->sin_port
= htons(port
);
249 return sizeof(struct sockaddr_in
);
252 static int is_multicast_address(struct sockaddr_in
*addr
)
254 return IN_MULTICAST(ntohl(addr
->sin_addr
.s_addr
));
257 static int udp_socket_create(UDPContext
*s
, struct sockaddr_in
*addr
, int *addr_len
)
261 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
265 addr
->sin_family
= AF_INET
;
266 addr
->sin_addr
.s_addr
= htonl (INADDR_ANY
);
267 addr
->sin_port
= htons(s
->local_port
);
268 *addr_len
= sizeof(struct sockaddr_in
);
273 static int udp_port(struct sockaddr_in
*addr
, int len
)
275 return ntohs(addr
->sin_port
);
277 #endif /* CONFIG_IPV6 */
281 * If no filename is given to av_open_input_file because you want to
282 * get the local port first, then you must call this function to set
283 * the remote server address.
285 * url syntax: udp://host:port[?option=val...]
286 * option: 'ttl=n' : set the ttl value (for multicast only)
287 * 'localport=n' : set the local port
288 * 'pkt_size=n' : set max packet size
289 * 'reuse=1' : enable reusing the socket
291 * @param s1 media file context
292 * @param uri of the remote server
293 * @return zero if no error.
295 int udp_set_remote_url(URLContext
*h
, const char *uri
)
297 UDPContext
*s
= h
->priv_data
;
301 url_split(NULL
, 0, NULL
, 0, hostname
, sizeof(hostname
), &port
, NULL
, 0, uri
);
303 /* set the destination address */
304 s
->dest_addr_len
= udp_set_url(&s
->dest_addr
, hostname
, port
);
305 if (s
->dest_addr_len
< 0) {
308 s
->is_multicast
= is_multicast_address(&s
->dest_addr
);
314 * Return the local port used by the UDP connexion
315 * @param s1 media file context
316 * @return the local port number
318 int udp_get_local_port(URLContext
*h
)
320 UDPContext
*s
= h
->priv_data
;
321 return s
->local_port
;
325 * Return the udp file handle for select() usage to wait for several RTP
326 * streams at the same time.
327 * @param h media file context
329 #if (LIBAVFORMAT_VERSION_MAJOR >= 53)
332 int udp_get_file_handle(URLContext
*h
)
334 UDPContext
*s
= h
->priv_data
;
338 /* put it in UDP context */
339 /* return non zero if error */
340 static int udp_open(URLContext
*h
, const char *uri
, int flags
)
343 int port
, udp_fd
= -1, tmp
, bind_ret
= -1;
344 UDPContext
*s
= NULL
;
349 struct sockaddr_in my_addr
;
351 struct sockaddr_storage my_addr
;
356 h
->max_packet_size
= 1472;
358 is_output
= (flags
& URL_WRONLY
);
360 if(!ff_network_init())
363 s
= av_mallocz(sizeof(UDPContext
));
365 return AVERROR(ENOMEM
);
369 s
->buffer_size
= is_output
? UDP_TX_BUF_SIZE
: UDP_MAX_PKT_SIZE
;
371 p
= strchr(uri
, '?');
373 s
->reuse_socket
= find_info_tag(buf
, sizeof(buf
), "reuse", p
);
374 if (find_info_tag(buf
, sizeof(buf
), "ttl", p
)) {
375 s
->ttl
= strtol(buf
, NULL
, 10);
377 if (find_info_tag(buf
, sizeof(buf
), "localport", p
)) {
378 s
->local_port
= strtol(buf
, NULL
, 10);
380 if (find_info_tag(buf
, sizeof(buf
), "pkt_size", p
)) {
381 h
->max_packet_size
= strtol(buf
, NULL
, 10);
383 if (find_info_tag(buf
, sizeof(buf
), "buffer_size", p
)) {
384 s
->buffer_size
= strtol(buf
, NULL
, 10);
388 /* fill the dest addr */
389 url_split(NULL
, 0, NULL
, 0, hostname
, sizeof(hostname
), &port
, NULL
, 0, uri
);
391 /* XXX: fix url_split */
392 if (hostname
[0] == '\0' || hostname
[0] == '?') {
393 /* only accepts null hostname if input */
394 if (flags
& URL_WRONLY
)
397 udp_set_remote_url(h
, uri
);
400 if (s
->is_multicast
&& !(h
->flags
& URL_WRONLY
))
401 s
->local_port
= port
;
402 udp_fd
= udp_socket_create(s
, &my_addr
, &len
);
407 if (setsockopt (udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &(s
->reuse_socket
), sizeof(s
->reuse_socket
)) != 0)
410 /* the bind is needed to give a port to the socket now */
411 /* if multicast, try the multicast address bind first */
412 if (s
->is_multicast
&& !(h
->flags
& URL_WRONLY
)) {
413 bind_ret
= bind(udp_fd
,(struct sockaddr
*)&s
->dest_addr
, len
);
415 /* bind to the local address if not multicast or if the multicast
417 if (bind_ret
< 0 && bind(udp_fd
,(struct sockaddr
*)&my_addr
, len
) < 0)
420 len
= sizeof(my_addr
);
421 getsockname(udp_fd
, (struct sockaddr
*)&my_addr
, &len
);
422 s
->local_port
= udp_port(&my_addr
, len
);
424 if (s
->is_multicast
) {
425 if (h
->flags
& URL_WRONLY
) {
427 if (udp_set_multicast_ttl(udp_fd
, s
->ttl
, (struct sockaddr
*)&s
->dest_addr
) < 0)
431 if (udp_join_multicast_group(udp_fd
, (struct sockaddr
*)&s
->dest_addr
) < 0)
437 /* limit the tx buf size to limit latency */
438 tmp
= s
->buffer_size
;
439 if (setsockopt(udp_fd
, SOL_SOCKET
, SO_SNDBUF
, &tmp
, sizeof(tmp
)) < 0) {
440 av_log(NULL
, AV_LOG_ERROR
, "setsockopt(SO_SNDBUF): %s\n", strerror(errno
));
444 /* set udp recv buffer size to the largest possible udp packet size to
445 * avoid losing data on OSes that set this too low by default. */
446 tmp
= s
->buffer_size
;
447 if (setsockopt(udp_fd
, SOL_SOCKET
, SO_RCVBUF
, &tmp
, sizeof(tmp
)) < 0) {
448 av_log(NULL
, AV_LOG_WARNING
, "setsockopt(SO_RECVBUF): %s\n", strerror(errno
));
450 /* make the socket non-blocking */
451 ff_socket_nonblock(udp_fd
, 1);
463 static int udp_read(URLContext
*h
, uint8_t *buf
, int size
)
465 UDPContext
*s
= h
->priv_data
;
472 if (url_interrupt_cb())
473 return AVERROR(EINTR
);
475 FD_SET(s
->udp_fd
, &rfds
);
477 tv
.tv_usec
= 100 * 1000;
478 ret
= select(s
->udp_fd
+ 1, &rfds
, NULL
, NULL
, &tv
);
481 if (!(ret
> 0 && FD_ISSET(s
->udp_fd
, &rfds
)))
483 len
= recv(s
->udp_fd
, buf
, size
, 0);
485 if (ff_neterrno() != FF_NETERROR(EAGAIN
) &&
486 ff_neterrno() != FF_NETERROR(EINTR
))
495 static int udp_write(URLContext
*h
, uint8_t *buf
, int size
)
497 UDPContext
*s
= h
->priv_data
;
501 ret
= sendto (s
->udp_fd
, buf
, size
, 0,
502 (struct sockaddr
*) &s
->dest_addr
,
505 if (ff_neterrno() != FF_NETERROR(EINTR
) &&
506 ff_neterrno() != FF_NETERROR(EAGAIN
))
515 static int udp_close(URLContext
*h
)
517 UDPContext
*s
= h
->priv_data
;
519 if (s
->is_multicast
&& !(h
->flags
& URL_WRONLY
))
520 udp_leave_multicast_group(s
->udp_fd
, (struct sockaddr
*)&s
->dest_addr
);
521 closesocket(s
->udp_fd
);
527 URLProtocol udp_protocol
= {
534 .url_get_file_handle
= udp_get_file_handle
,