Fix memleak on some OSes in case network initialization fails. See
[libav.git] / libavformat / udp.c
CommitLineData
de6d9b64
FB
1/*
2 * UDP prototype streaming system
2d225591 3 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard.
de6d9b64 4 *
b78e7197
DB
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
19720f15
FB
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
b78e7197 10 * version 2.1 of the License, or (at your option) any later version.
de6d9b64 11 *
b78e7197 12 * FFmpeg is distributed in the hope that it will be useful,
de6d9b64 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19720f15
FB
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
de6d9b64 16 *
19720f15 17 * You should have received a copy of the GNU Lesser General Public
b78e7197 18 * License along with FFmpeg; if not, write to the Free Software
5509bffa 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
de6d9b64 20 */
3adfb377
LB
21
22/**
23 * @file udp.c
24 * UDP protocol
25 */
26
8be1c656 27#include "avformat.h"
de6d9b64 28#include <unistd.h>
42572ef5 29#include "network.h"
087b3272 30#include "os_support.h"
de6d9b64 31
9c633e9a
AB
32#ifndef IPV6_ADD_MEMBERSHIP
33#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
34#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
35#endif
35b74c3d
LA
36#ifndef IN_MULTICAST
37#define IN_MULTICAST(a) ((((uint32_t)(a)) & 0xf0000000) == 0xe0000000)
38#endif
39#ifndef IN6_IS_ADDR_MULTICAST
40#define IN6_IS_ADDR_MULTICAST(a) (((uint8_t *) (a))[0] == 0xff)
41#endif
9c633e9a 42
de6d9b64 43typedef struct {
2d225591
FB
44 int udp_fd;
45 int ttl;
46 int is_multicast;
47 int local_port;
34ecc397 48 int reuse_socket;
7a91333f 49#ifndef CONFIG_IPV6
2d225591 50 struct sockaddr_in dest_addr;
7a91333f
HZ
51#else
52 struct sockaddr_storage dest_addr;
7a91333f 53#endif
397db8ac 54 int dest_addr_len;
de6d9b64
FB
55} UDPContext;
56
57#define UDP_TX_BUF_SIZE 32768
f18cae4d 58#define UDP_MAX_PKT_SIZE 65536
de6d9b64 59
9cdcb04f 60static int udp_set_multicast_ttl(int sockfd, int mcastTTL, struct sockaddr *addr) {
a8bde059 61#ifdef IP_MULTICAST_TTL
7a91333f
HZ
62 if (addr->sa_family == AF_INET) {
63 if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &mcastTTL, sizeof(mcastTTL)) < 0) {
086119b3 64 av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_TTL): %s\n", strerror(errno));
7a91333f
HZ
65 return -1;
66 }
67 }
a8bde059
LA
68#endif
69#ifdef CONFIG_IPV6
7a91333f
HZ
70 if (addr->sa_family == AF_INET6) {
71 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastTTL, sizeof(mcastTTL)) < 0) {
086119b3 72 av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_HOPS): %s\n", strerror(errno));
7a91333f
HZ
73 return -1;
74 }
75 }
a8bde059 76#endif
7a91333f
HZ
77 return 0;
78}
79
9cdcb04f 80static int udp_join_multicast_group(int sockfd, struct sockaddr *addr) {
a8bde059 81#ifdef IP_ADD_MEMBERSHIP
7a91333f 82 if (addr->sa_family == AF_INET) {
a8bde059
LA
83 struct ip_mreq mreq;
84
7a91333f
HZ
85 mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
86 mreq.imr_interface.s_addr= INADDR_ANY;
87 if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
086119b3 88 av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno));
7a91333f
HZ
89 return -1;
90 }
91 }
a8bde059
LA
92#endif
93#ifdef CONFIG_IPV6
7a91333f 94 if (addr->sa_family == AF_INET6) {
a8bde059
LA
95 struct ipv6_mreq mreq6;
96
7a91333f
HZ
97 memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
98 mreq6.ipv6mr_interface= 0;
99 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
086119b3 100 av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP): %s\n", strerror(errno));
7a91333f
HZ
101 return -1;
102 }
103 }
a8bde059 104#endif
7a91333f
HZ
105 return 0;
106}
107
9cdcb04f 108static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr) {
a8bde059 109#ifdef IP_DROP_MEMBERSHIP
7a91333f 110 if (addr->sa_family == AF_INET) {
a8bde059
LA
111 struct ip_mreq mreq;
112
7a91333f
HZ
113 mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
114 mreq.imr_interface.s_addr= INADDR_ANY;
115 if (setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
086119b3 116 av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_DROP_MEMBERSHIP): %s\n", strerror(errno));
7a91333f
HZ
117 return -1;
118 }
119 }
a8bde059
LA
120#endif
121#ifdef CONFIG_IPV6
7a91333f 122 if (addr->sa_family == AF_INET6) {
a8bde059
LA
123 struct ipv6_mreq mreq6;
124
7a91333f
HZ
125 memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
126 mreq6.ipv6mr_interface= 0;
127 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
086119b3 128 av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP): %s\n", strerror(errno));
7a91333f
HZ
129 return -1;
130 }
131 }
a8bde059 132#endif
7a91333f
HZ
133 return 0;
134}
135
a8bde059 136#ifdef CONFIG_IPV6
7b49ce2e 137static struct addrinfo* udp_ipv6_resolve_host(const char *hostname, int port, int type, int family, int flags) {
7a91333f
HZ
138 struct addrinfo hints, *res = 0;
139 int error;
140 char sport[16];
d607861c 141 const char *node = 0, *service = "0";
7a91333f
HZ
142
143 if (port > 0) {
2fc8ea24 144 snprintf(sport, sizeof(sport), "%d", port);
7a91333f
HZ
145 service = sport;
146 }
147 if ((hostname) && (hostname[0] != '\0') && (hostname[0] != '?')) {
148 node = hostname;
149 }
7d8576c2
LA
150 memset(&hints, 0, sizeof(hints));
151 hints.ai_socktype = type;
152 hints.ai_family = family;
153 hints.ai_flags = flags;
154 if ((error = getaddrinfo(node, service, &hints, &res))) {
155 av_log(NULL, AV_LOG_ERROR, "udp_ipv6_resolve_host: %s\n", gai_strerror(error));
156 }
157
7a91333f
HZ
158 return res;
159}
160
d05cb726 161static int udp_set_url(struct sockaddr_storage *addr, const char *hostname, int port) {
7a91333f 162 struct addrinfo *res0;
d05cb726
LA
163 int addr_len;
164
7a91333f 165 res0 = udp_ipv6_resolve_host(hostname, port, SOCK_DGRAM, AF_UNSPEC, 0);
6f3e0b21 166 if (res0 == 0) return AVERROR(EIO);
d05cb726
LA
167 memcpy(addr, res0->ai_addr, res0->ai_addrlen);
168 addr_len = res0->ai_addrlen;
7a91333f 169 freeaddrinfo(res0);
d05cb726
LA
170
171 return addr_len;
7a91333f
HZ
172}
173
35b74c3d
LA
174static int is_multicast_address(struct sockaddr_storage *addr)
175{
176 if (addr->ss_family == AF_INET) {
177 return IN_MULTICAST(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr));
178 }
179 if (addr->ss_family == AF_INET6) {
180 return IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)addr)->sin6_addr);
181 }
182
183 return 0;
184}
185
aa519c47
LA
186static int udp_socket_create(UDPContext *s, struct sockaddr_storage *addr, int *addr_len)
187{
7a91333f 188 int udp_fd = -1;
276358c1 189 struct addrinfo *res0 = NULL, *res = NULL;
51844e6c 190 int family = AF_UNSPEC;
115329f1 191
51844e6c
RB
192 if (((struct sockaddr *) &s->dest_addr)->sa_family)
193 family = ((struct sockaddr *) &s->dest_addr)->sa_family;
194 res0 = udp_ipv6_resolve_host(0, s->local_port, SOCK_DGRAM, family, AI_PASSIVE);
7d8576c2
LA
195 if (res0 == 0)
196 goto fail;
197 for (res = res0; res; res=res->ai_next) {
198 udp_fd = socket(res->ai_family, SOCK_DGRAM, 0);
199 if (udp_fd > 0) break;
086119b3 200 av_log(NULL, AV_LOG_ERROR, "socket: %s\n", strerror(errno));
7d8576c2 201 }
276358c1
HZ
202
203 if (udp_fd < 0)
7a91333f 204 goto fail;
115329f1 205
aa519c47
LA
206 memcpy(addr, res->ai_addr, res->ai_addrlen);
207 *addr_len = res->ai_addrlen;
7a91333f 208
aa519c47 209 freeaddrinfo(res0);
115329f1 210
7a91333f 211 return udp_fd;
115329f1 212
7a91333f
HZ
213 fail:
214 if (udp_fd >= 0)
7a91333f 215 closesocket(udp_fd);
88730be6
MR
216 if(res0)
217 freeaddrinfo(res0);
7a91333f
HZ
218 return -1;
219}
220
aa519c47
LA
221static int udp_port(struct sockaddr_storage *addr, int addr_len)
222{
03c09e43 223 char sbuf[sizeof(int)*3+1];
aa519c47 224
03c09e43 225 if (getnameinfo((struct sockaddr *)addr, addr_len, NULL, 0, sbuf, sizeof(sbuf), NI_NUMERICSERV) != 0) {
086119b3 226 av_log(NULL, AV_LOG_ERROR, "getnameinfo: %s\n", strerror(errno));
aa519c47
LA
227 return -1;
228 }
229
230 return strtol(sbuf, NULL, 10);
231}
232
d05cb726
LA
233#else
234
235static int udp_set_url(struct sockaddr_in *addr, const char *hostname, int port)
236{
237 /* set the destination address */
238 if (resolve_host(&addr->sin_addr, hostname) < 0)
239 return AVERROR(EIO);
240 addr->sin_family = AF_INET;
241 addr->sin_port = htons(port);
242
243 return sizeof(struct sockaddr_in);
244}
245
35b74c3d
LA
246static int is_multicast_address(struct sockaddr_in *addr)
247{
248 return IN_MULTICAST(ntohl(addr->sin_addr.s_addr));
249}
250
aa519c47
LA
251static int udp_socket_create(UDPContext *s, struct sockaddr_in *addr, int *addr_len)
252{
253 int fd;
254
255 fd = socket(AF_INET, SOCK_DGRAM, 0);
256 if (fd < 0)
257 return -1;
258
259 addr->sin_family = AF_INET;
260 addr->sin_addr.s_addr = htonl (INADDR_ANY);
261 addr->sin_port = htons(s->local_port);
262 *addr_len = sizeof(struct sockaddr_in);
263
264 return fd;
265}
266
267static int udp_port(struct sockaddr_in *addr, int len)
268{
269 return ntohs(addr->sin_port);
270}
0a4f20c6 271#endif /* CONFIG_IPV6 */
7a91333f
HZ
272
273
2d225591
FB
274/**
275 * If no filename is given to av_open_input_file because you want to
276 * get the local port first, then you must call this function to set
277 * the remote server address.
278 *
279 * url syntax: udp://host:port[?option=val...]
35b74c3d 280 * option: 'ttl=n' : set the ttl value (for multicast only)
2d225591 281 * 'localport=n' : set the local port
9899efb4 282 * 'pkt_size=n' : set max packet size
34ecc397 283 * 'reuse=1' : enable reusing the socket
2d225591
FB
284 *
285 * @param s1 media file context
286 * @param uri of the remote server
287 * @return zero if no error.
288 */
289int udp_set_remote_url(URLContext *h, const char *uri)
290{
291 UDPContext *s = h->priv_data;
292 char hostname[256];
293 int port;
115329f1 294
6ba5cbc6 295 url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
de6d9b64 296
2d225591 297 /* set the destination address */
d05cb726
LA
298 s->dest_addr_len = udp_set_url(&s->dest_addr, hostname, port);
299 if (s->dest_addr_len < 0) {
6f3e0b21 300 return AVERROR(EIO);
d05cb726 301 }
35b74c3d 302 s->is_multicast = is_multicast_address(&s->dest_addr);
d05cb726 303
2d225591
FB
304 return 0;
305}
306
307/**
308 * Return the local port used by the UDP connexion
309 * @param s1 media file context
310 * @return the local port number
311 */
312int udp_get_local_port(URLContext *h)
313{
314 UDPContext *s = h->priv_data;
315 return s->local_port;
316}
317
318/**
319 * Return the udp file handle for select() usage to wait for several RTP
320 * streams at the same time.
321 * @param h media file context
322 */
323int udp_get_file_handle(URLContext *h)
324{
325 UDPContext *s = h->priv_data;
326 return s->udp_fd;
327}
328
329/* put it in UDP context */
de6d9b64
FB
330/* return non zero if error */
331static int udp_open(URLContext *h, const char *uri, int flags)
332{
de6d9b64 333 char hostname[1024];
2d225591
FB
334 int port, udp_fd = -1, tmp;
335 UDPContext *s = NULL;
88730be6 336 int is_output;
2d225591
FB
337 const char *p;
338 char buf[256];
88730be6 339#ifndef CONFIG_IPV6
d4936869 340 struct sockaddr_in my_addr;
aa519c47
LA
341#else
342 struct sockaddr_storage my_addr;
88730be6 343#endif
aa519c47 344 int len;
de6d9b64
FB
345
346 h->is_streamed = 1;
9899efb4 347 h->max_packet_size = 1472;
de6d9b64 348
2d225591 349 is_output = (flags & URL_WRONLY);
115329f1 350
e6c13819
RB
351 if(!ff_network_init())
352 return AVERROR(EIO);
353
51844e6c 354 s = av_mallocz(sizeof(UDPContext));
2d225591 355 if (!s)
8fa36ae0 356 return AVERROR(ENOMEM);
2d225591
FB
357
358 h->priv_data = s;
359 s->ttl = 16;
2d225591
FB
360 p = strchr(uri, '?');
361 if (p) {
34ecc397 362 s->reuse_socket = find_info_tag(buf, sizeof(buf), "reuse", p);
2d225591
FB
363 if (find_info_tag(buf, sizeof(buf), "ttl", p)) {
364 s->ttl = strtol(buf, NULL, 10);
365 }
366 if (find_info_tag(buf, sizeof(buf), "localport", p)) {
367 s->local_port = strtol(buf, NULL, 10);
368 }
9899efb4
MK
369 if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
370 h->max_packet_size = strtol(buf, NULL, 10);
371 }
de6d9b64 372 }
2d225591
FB
373
374 /* fill the dest addr */
6ba5cbc6 375 url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
115329f1 376
2d225591
FB
377 /* XXX: fix url_split */
378 if (hostname[0] == '\0' || hostname[0] == '?') {
379 /* only accepts null hostname if input */
35b74c3d 380 if (flags & URL_WRONLY)
2d225591
FB
381 goto fail;
382 } else {
383 udp_set_remote_url(h, uri);
384 }
de6d9b64 385
882d00f2
LA
386 if (s->is_multicast && !(h->flags & URL_WRONLY))
387 s->local_port = port;
aa519c47 388 udp_fd = udp_socket_create(s, &my_addr, &len);
2d225591
FB
389 if (udp_fd < 0)
390 goto fail;
391
34ecc397
T
392 if (s->reuse_socket)
393 if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0)
394 goto fail;
395
de6d9b64 396 /* the bind is needed to give a port to the socket now */
aa519c47 397 if (bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0)
de6d9b64
FB
398 goto fail;
399
d4936869
LA
400 len = sizeof(my_addr);
401 getsockname(udp_fd, (struct sockaddr *)&my_addr, &len);
aa519c47
LA
402 s->local_port = udp_port(&my_addr, len);
403
7a91333f
HZ
404 if (s->is_multicast) {
405 if (h->flags & URL_WRONLY) {
a8bde059 406 /* output */
9cdcb04f 407 if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0)
7a91333f
HZ
408 goto fail;
409 } else {
a8bde059 410 /* input */
9cdcb04f 411 if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0)
7a91333f
HZ
412 goto fail;
413 }
414 }
de6d9b64 415
2d225591
FB
416 if (is_output) {
417 /* limit the tx buf size to limit latency */
418 tmp = UDP_TX_BUF_SIZE;
419 if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) {
086119b3 420 av_log(NULL, AV_LOG_ERROR, "setsockopt(SO_SNDBUF): %s\n", strerror(errno));
2d225591
FB
421 goto fail;
422 }
f18cae4d
RP
423 } else {
424 /* set udp recv buffer size to the largest possible udp packet size to
425 * avoid losing data on OSes that set this too low by default. */
426 tmp = UDP_MAX_PKT_SIZE;
427 setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp));
2d225591
FB
428 }
429
430 s->udp_fd = udp_fd;
de6d9b64
FB
431 return 0;
432 fail:
2d225591 433 if (udp_fd >= 0)
9ddd71fc 434 closesocket(udp_fd);
2d225591 435 av_free(s);
6f3e0b21 436 return AVERROR(EIO);
de6d9b64
FB
437}
438
0c1a9eda 439static int udp_read(URLContext *h, uint8_t *buf, int size)
de6d9b64
FB
440{
441 UDPContext *s = h->priv_data;
191e8ca7 442 int len;
2d225591
FB
443
444 for(;;) {
4c7d5764 445 len = recv(s->udp_fd, buf, size, 0);
2d225591 446 if (len < 0) {
8da4034f
AB
447 if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
448 ff_neterrno() != FF_NETERROR(EINTR))
6f3e0b21 449 return AVERROR(EIO);
2d225591
FB
450 } else {
451 break;
452 }
453 }
454 return len;
de6d9b64
FB
455}
456
0c1a9eda 457static int udp_write(URLContext *h, uint8_t *buf, int size)
de6d9b64
FB
458{
459 UDPContext *s = h->priv_data;
2d225591
FB
460 int ret;
461
462 for(;;) {
115329f1 463 ret = sendto (s->udp_fd, buf, size, 0,
2d225591 464 (struct sockaddr *) &s->dest_addr,
7a91333f 465 s->dest_addr_len);
2d225591 466 if (ret < 0) {
8da4034f
AB
467 if (ff_neterrno() != FF_NETERROR(EINTR) &&
468 ff_neterrno() != FF_NETERROR(EAGAIN))
6f3e0b21 469 return AVERROR(EIO);
2d225591
FB
470 } else {
471 break;
472 }
de6d9b64 473 }
2d225591
FB
474 return size;
475}
476
477static int udp_close(URLContext *h)
478{
479 UDPContext *s = h->priv_data;
480
7a91333f 481 if (s->is_multicast && !(h->flags & URL_WRONLY))
9cdcb04f 482 udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr);
9ddd71fc 483 closesocket(s->udp_fd);
1642cb6b 484 ff_network_close();
2d225591
FB
485 av_free(s);
486 return 0;
de6d9b64
FB
487}
488
489URLProtocol udp_protocol = {
490 "udp",
491 udp_open,
2d225591 492 udp_read,
de6d9b64
FB
493 udp_write,
494 NULL, /* seek */
495 udp_close,
496};