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
27 #define _BSD_SOURCE /* Needed for using struct ip_mreq with recent glibc */
31 #include "os_support.h"
32 #ifdef HAVE_SYS_SELECT_H
33 #include <sys/select.h>
36 #ifndef IPV6_ADD_MEMBERSHIP
37 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
38 #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
41 #define IN_MULTICAST(a) ((((uint32_t)(a)) & 0xf0000000) == 0xe0000000)
43 #ifndef IN6_IS_ADDR_MULTICAST
44 #define IN6_IS_ADDR_MULTICAST(a) (((uint8_t *) (a))[0] == 0xff)
55 struct sockaddr_in dest_addr
;
57 struct sockaddr_storage dest_addr
;
62 #define UDP_TX_BUF_SIZE 32768
63 #define UDP_MAX_PKT_SIZE 65536
65 static int udp_set_multicast_ttl(int sockfd
, int mcastTTL
, struct sockaddr
*addr
) {
66 #ifdef IP_MULTICAST_TTL
67 if (addr
->sa_family
== AF_INET
) {
68 if (setsockopt(sockfd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &mcastTTL
, sizeof(mcastTTL
)) < 0) {
69 av_log(NULL
, AV_LOG_ERROR
, "setsockopt(IP_MULTICAST_TTL): %s\n", strerror(errno
));
75 if (addr
->sa_family
== AF_INET6
) {
76 if (setsockopt(sockfd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &mcastTTL
, sizeof(mcastTTL
)) < 0) {
77 av_log(NULL
, AV_LOG_ERROR
, "setsockopt(IPV6_MULTICAST_HOPS): %s\n", strerror(errno
));
85 static int udp_join_multicast_group(int sockfd
, struct sockaddr
*addr
) {
86 #ifdef IP_ADD_MEMBERSHIP
87 if (addr
->sa_family
== AF_INET
) {
90 mreq
.imr_multiaddr
.s_addr
= ((struct sockaddr_in
*)addr
)->sin_addr
.s_addr
;
91 mreq
.imr_interface
.s_addr
= INADDR_ANY
;
92 if (setsockopt(sockfd
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (const void *)&mreq
, sizeof(mreq
)) < 0) {
93 av_log(NULL
, AV_LOG_ERROR
, "setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno
));
99 if (addr
->sa_family
== AF_INET6
) {
100 struct ipv6_mreq mreq6
;
102 memcpy(&mreq6
.ipv6mr_multiaddr
, &(((struct sockaddr_in6
*)addr
)->sin6_addr
), sizeof(struct in6_addr
));
103 mreq6
.ipv6mr_interface
= 0;
104 if (setsockopt(sockfd
, IPPROTO_IPV6
, IPV6_ADD_MEMBERSHIP
, &mreq6
, sizeof(mreq6
)) < 0) {
105 av_log(NULL
, AV_LOG_ERROR
, "setsockopt(IPV6_ADD_MEMBERSHIP): %s\n", strerror(errno
));
113 static int udp_leave_multicast_group(int sockfd
, struct sockaddr
*addr
) {
114 #ifdef IP_DROP_MEMBERSHIP
115 if (addr
->sa_family
== AF_INET
) {
118 mreq
.imr_multiaddr
.s_addr
= ((struct sockaddr_in
*)addr
)->sin_addr
.s_addr
;
119 mreq
.imr_interface
.s_addr
= INADDR_ANY
;
120 if (setsockopt(sockfd
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
, (const void *)&mreq
, sizeof(mreq
)) < 0) {
121 av_log(NULL
, AV_LOG_ERROR
, "setsockopt(IP_DROP_MEMBERSHIP): %s\n", strerror(errno
));
127 if (addr
->sa_family
== AF_INET6
) {
128 struct ipv6_mreq mreq6
;
130 memcpy(&mreq6
.ipv6mr_multiaddr
, &(((struct sockaddr_in6
*)addr
)->sin6_addr
), sizeof(struct in6_addr
));
131 mreq6
.ipv6mr_interface
= 0;
132 if (setsockopt(sockfd
, IPPROTO_IPV6
, IPV6_DROP_MEMBERSHIP
, &mreq6
, sizeof(mreq6
)) < 0) {
133 av_log(NULL
, AV_LOG_ERROR
, "setsockopt(IPV6_DROP_MEMBERSHIP): %s\n", strerror(errno
));
142 static struct addrinfo
* udp_ipv6_resolve_host(const char *hostname
, int port
, int type
, int family
, int flags
) {
143 struct addrinfo hints
, *res
= 0;
146 const char *node
= 0, *service
= "0";
149 snprintf(sport
, sizeof(sport
), "%d", port
);
152 if ((hostname
) && (hostname
[0] != '\0') && (hostname
[0] != '?')) {
155 memset(&hints
, 0, sizeof(hints
));
156 hints
.ai_socktype
= type
;
157 hints
.ai_family
= family
;
158 hints
.ai_flags
= flags
;
159 if ((error
= getaddrinfo(node
, service
, &hints
, &res
))) {
160 av_log(NULL
, AV_LOG_ERROR
, "udp_ipv6_resolve_host: %s\n", gai_strerror(error
));
166 static int udp_set_url(struct sockaddr_storage
*addr
, const char *hostname
, int port
) {
167 struct addrinfo
*res0
;
170 res0
= udp_ipv6_resolve_host(hostname
, port
, SOCK_DGRAM
, AF_UNSPEC
, 0);
171 if (res0
== 0) return AVERROR(EIO
);
172 memcpy(addr
, res0
->ai_addr
, res0
->ai_addrlen
);
173 addr_len
= res0
->ai_addrlen
;
179 static int is_multicast_address(struct sockaddr_storage
*addr
)
181 if (addr
->ss_family
== AF_INET
) {
182 return IN_MULTICAST(ntohl(((struct sockaddr_in
*)addr
)->sin_addr
.s_addr
));
184 if (addr
->ss_family
== AF_INET6
) {
185 return IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6
*)addr
)->sin6_addr
);
191 static int udp_socket_create(UDPContext
*s
, struct sockaddr_storage
*addr
, int *addr_len
)
194 struct addrinfo
*res0
= NULL
, *res
= NULL
;
195 int family
= AF_UNSPEC
;
197 if (((struct sockaddr
*) &s
->dest_addr
)->sa_family
)
198 family
= ((struct sockaddr
*) &s
->dest_addr
)->sa_family
;
199 res0
= udp_ipv6_resolve_host(0, s
->local_port
, SOCK_DGRAM
, family
, AI_PASSIVE
);
202 for (res
= res0
; res
; res
=res
->ai_next
) {
203 udp_fd
= socket(res
->ai_family
, SOCK_DGRAM
, 0);
204 if (udp_fd
> 0) break;
205 av_log(NULL
, AV_LOG_ERROR
, "socket: %s\n", strerror(errno
));
211 memcpy(addr
, res
->ai_addr
, res
->ai_addrlen
);
212 *addr_len
= res
->ai_addrlen
;
226 static int udp_port(struct sockaddr_storage
*addr
, int addr_len
)
228 char sbuf
[sizeof(int)*3+1];
230 if (getnameinfo((struct sockaddr
*)addr
, addr_len
, NULL
, 0, sbuf
, sizeof(sbuf
), NI_NUMERICSERV
) != 0) {
231 av_log(NULL
, AV_LOG_ERROR
, "getnameinfo: %s\n", strerror(errno
));
235 return strtol(sbuf
, NULL
, 10);
240 static int udp_set_url(struct sockaddr_in
*addr
, const char *hostname
, int port
)
242 /* set the destination address */
243 if (resolve_host(&addr
->sin_addr
, hostname
) < 0)
245 addr
->sin_family
= AF_INET
;
246 addr
->sin_port
= htons(port
);
248 return sizeof(struct sockaddr_in
);
251 static int is_multicast_address(struct sockaddr_in
*addr
)
253 return IN_MULTICAST(ntohl(addr
->sin_addr
.s_addr
));
256 static int udp_socket_create(UDPContext
*s
, struct sockaddr_in
*addr
, int *addr_len
)
260 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
264 addr
->sin_family
= AF_INET
;
265 addr
->sin_addr
.s_addr
= htonl (INADDR_ANY
);
266 addr
->sin_port
= htons(s
->local_port
);
267 *addr_len
= sizeof(struct sockaddr_in
);
272 static int udp_port(struct sockaddr_in
*addr
, int len
)
274 return ntohs(addr
->sin_port
);
276 #endif /* CONFIG_IPV6 */
280 * If no filename is given to av_open_input_file because you want to
281 * get the local port first, then you must call this function to set
282 * the remote server address.
284 * url syntax: udp://host:port[?option=val...]
285 * option: 'ttl=n' : set the ttl value (for multicast only)
286 * 'localport=n' : set the local port
287 * 'pkt_size=n' : set max packet size
288 * 'reuse=1' : enable reusing the socket
290 * @param s1 media file context
291 * @param uri of the remote server
292 * @return zero if no error.
294 int udp_set_remote_url(URLContext
*h
, const char *uri
)
296 UDPContext
*s
= h
->priv_data
;
300 url_split(NULL
, 0, NULL
, 0, hostname
, sizeof(hostname
), &port
, NULL
, 0, uri
);
302 /* set the destination address */
303 s
->dest_addr_len
= udp_set_url(&s
->dest_addr
, hostname
, port
);
304 if (s
->dest_addr_len
< 0) {
307 s
->is_multicast
= is_multicast_address(&s
->dest_addr
);
313 * Return the local port used by the UDP connexion
314 * @param s1 media file context
315 * @return the local port number
317 int udp_get_local_port(URLContext
*h
)
319 UDPContext
*s
= h
->priv_data
;
320 return s
->local_port
;
324 * Return the udp file handle for select() usage to wait for several RTP
325 * streams at the same time.
326 * @param h media file context
328 int udp_get_file_handle(URLContext
*h
)
330 UDPContext
*s
= h
->priv_data
;
334 /* put it in UDP context */
335 /* return non zero if error */
336 static int udp_open(URLContext
*h
, const char *uri
, int flags
)
339 int port
, udp_fd
= -1, tmp
;
340 UDPContext
*s
= NULL
;
345 struct sockaddr_in my_addr
;
347 struct sockaddr_storage my_addr
;
352 h
->max_packet_size
= 1472;
354 is_output
= (flags
& URL_WRONLY
);
356 if(!ff_network_init())
359 s
= av_mallocz(sizeof(UDPContext
));
361 return AVERROR(ENOMEM
);
365 s
->buffer_size
= is_output
? UDP_TX_BUF_SIZE
: UDP_MAX_PKT_SIZE
;
367 p
= strchr(uri
, '?');
369 s
->reuse_socket
= find_info_tag(buf
, sizeof(buf
), "reuse", p
);
370 if (find_info_tag(buf
, sizeof(buf
), "ttl", p
)) {
371 s
->ttl
= strtol(buf
, NULL
, 10);
373 if (find_info_tag(buf
, sizeof(buf
), "localport", p
)) {
374 s
->local_port
= strtol(buf
, NULL
, 10);
376 if (find_info_tag(buf
, sizeof(buf
), "pkt_size", p
)) {
377 h
->max_packet_size
= strtol(buf
, NULL
, 10);
379 if (find_info_tag(buf
, sizeof(buf
), "buffer_size", p
)) {
380 s
->buffer_size
= strtol(buf
, NULL
, 10);
384 /* fill the dest addr */
385 url_split(NULL
, 0, NULL
, 0, hostname
, sizeof(hostname
), &port
, NULL
, 0, uri
);
387 /* XXX: fix url_split */
388 if (hostname
[0] == '\0' || hostname
[0] == '?') {
389 /* only accepts null hostname if input */
390 if (flags
& URL_WRONLY
)
393 udp_set_remote_url(h
, uri
);
396 if (s
->is_multicast
&& !(h
->flags
& URL_WRONLY
))
397 s
->local_port
= port
;
398 udp_fd
= udp_socket_create(s
, &my_addr
, &len
);
403 if (setsockopt (udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &(s
->reuse_socket
), sizeof(s
->reuse_socket
)) != 0)
406 /* the bind is needed to give a port to the socket now */
407 if (bind(udp_fd
,(struct sockaddr
*)&my_addr
, len
) < 0)
410 len
= sizeof(my_addr
);
411 getsockname(udp_fd
, (struct sockaddr
*)&my_addr
, &len
);
412 s
->local_port
= udp_port(&my_addr
, len
);
414 if (s
->is_multicast
) {
415 if (h
->flags
& URL_WRONLY
) {
417 if (udp_set_multicast_ttl(udp_fd
, s
->ttl
, (struct sockaddr
*)&s
->dest_addr
) < 0)
421 if (udp_join_multicast_group(udp_fd
, (struct sockaddr
*)&s
->dest_addr
) < 0)
427 /* limit the tx buf size to limit latency */
428 tmp
= s
->buffer_size
;
429 if (setsockopt(udp_fd
, SOL_SOCKET
, SO_SNDBUF
, &tmp
, sizeof(tmp
)) < 0) {
430 av_log(NULL
, AV_LOG_ERROR
, "setsockopt(SO_SNDBUF): %s\n", strerror(errno
));
434 /* set udp recv buffer size to the largest possible udp packet size to
435 * avoid losing data on OSes that set this too low by default. */
436 tmp
= s
->buffer_size
;
437 if (setsockopt(udp_fd
, SOL_SOCKET
, SO_RCVBUF
, &tmp
, sizeof(tmp
)) < 0) {
438 av_log(NULL
, AV_LOG_WARNING
, "setsockopt(SO_RECVBUF): %s\n", strerror(errno
));
440 /* make the socket non-blocking */
441 ff_socket_nonblock(udp_fd
, 1);
453 static int udp_read(URLContext
*h
, uint8_t *buf
, int size
)
455 UDPContext
*s
= h
->priv_data
;
462 if (url_interrupt_cb())
463 return AVERROR(EINTR
);
465 FD_SET(s
->udp_fd
, &rfds
);
467 tv
.tv_usec
= 100 * 1000;
468 ret
= select(s
->udp_fd
+ 1, &rfds
, NULL
, NULL
, &tv
);
471 if (!(ret
> 0 && FD_ISSET(s
->udp_fd
, &rfds
)))
473 len
= recv(s
->udp_fd
, buf
, size
, 0);
475 if (ff_neterrno() != FF_NETERROR(EAGAIN
) &&
476 ff_neterrno() != FF_NETERROR(EINTR
))
485 static int udp_write(URLContext
*h
, uint8_t *buf
, int size
)
487 UDPContext
*s
= h
->priv_data
;
491 ret
= sendto (s
->udp_fd
, buf
, size
, 0,
492 (struct sockaddr
*) &s
->dest_addr
,
495 if (ff_neterrno() != FF_NETERROR(EINTR
) &&
496 ff_neterrno() != FF_NETERROR(EAGAIN
))
505 static int udp_close(URLContext
*h
)
507 UDPContext
*s
= h
->priv_data
;
509 if (s
->is_multicast
&& !(h
->flags
& URL_WRONLY
))
510 udp_leave_multicast_group(s
->udp_fd
, (struct sockaddr
*)&s
->dest_addr
);
511 closesocket(s
->udp_fd
);
517 URLProtocol udp_protocol
= {