Statistics
| Branch: | Revision:

ffmpeg / libavformat / udp.c @ 470bce2b

History | View | Annotate | Download (15 KB)

1
/*
2
 * UDP prototype streaming system
3
 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard.
4
 *
5
 * This file is part of FFmpeg.
6
 *
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.
11
 *
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.
16
 *
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
20
 */
21

    
22
/**
23
 * @file udp.c
24
 * UDP protocol
25
 */
26

    
27
#define _BSD_SOURCE     /* Needed for using struct ip_mreq with recent glibc */
28
#include "avformat.h"
29
#include <unistd.h>
30
#include "network.h"
31
#include "os_support.h"
32
#ifdef HAVE_SYS_SELECT_H
33
#include <sys/select.h>
34
#endif
35
#include <sys/time.h>
36

    
37
#ifndef IPV6_ADD_MEMBERSHIP
38
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
39
#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
40
#endif
41
#ifndef IN_MULTICAST
42
#define IN_MULTICAST(a) ((((uint32_t)(a)) & 0xf0000000) == 0xe0000000)
43
#endif
44
#ifndef IN6_IS_ADDR_MULTICAST
45
#define IN6_IS_ADDR_MULTICAST(a) (((uint8_t *) (a))[0] == 0xff)
46
#endif
47

    
48
typedef struct {
49
    int udp_fd;
50
    int ttl;
51
    int buffer_size;
52
    int is_multicast;
53
    int local_port;
54
    int reuse_socket;
55
#ifndef CONFIG_IPV6
56
    struct sockaddr_in dest_addr;
57
#else
58
    struct sockaddr_storage dest_addr;
59
#endif
60
    int dest_addr_len;
61
} UDPContext;
62

    
63
#define UDP_TX_BUF_SIZE 32768
64
#define UDP_MAX_PKT_SIZE 65536
65

    
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));
71
            return -1;
72
        }
73
    }
74
#endif
75
#ifdef CONFIG_IPV6
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));
79
            return -1;
80
        }
81
    }
82
#endif
83
    return 0;
84
}
85

    
86
static int udp_join_multicast_group(int sockfd, struct sockaddr *addr) {
87
#ifdef IP_ADD_MEMBERSHIP
88
    if (addr->sa_family == AF_INET) {
89
        struct ip_mreq mreq;
90

    
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));
95
            return -1;
96
        }
97
    }
98
#endif
99
#ifdef CONFIG_IPV6
100
    if (addr->sa_family == AF_INET6) {
101
        struct ipv6_mreq mreq6;
102

    
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));
107
            return -1;
108
        }
109
    }
110
#endif
111
    return 0;
112
}
113

    
114
static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr) {
115
#ifdef IP_DROP_MEMBERSHIP
116
    if (addr->sa_family == AF_INET) {
117
        struct ip_mreq mreq;
118

    
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));
123
            return -1;
124
        }
125
    }
126
#endif
127
#ifdef CONFIG_IPV6
128
    if (addr->sa_family == AF_INET6) {
129
        struct ipv6_mreq mreq6;
130

    
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));
135
            return -1;
136
        }
137
    }
138
#endif
139
    return 0;
140
}
141

    
142
#ifdef CONFIG_IPV6
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;
145
    int error;
146
    char sport[16];
147
    const char *node = 0, *service = "0";
148

    
149
    if (port > 0) {
150
        snprintf(sport, sizeof(sport), "%d", port);
151
        service = sport;
152
    }
153
    if ((hostname) && (hostname[0] != '\0') && (hostname[0] != '?')) {
154
        node = hostname;
155
    }
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));
162
    }
163

    
164
    return res;
165
}
166

    
167
static int udp_set_url(struct sockaddr_storage *addr, const char *hostname, int port) {
168
    struct addrinfo *res0;
169
    int addr_len;
170

    
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;
175
    freeaddrinfo(res0);
176

    
177
    return addr_len;
178
}
179

    
180
static int is_multicast_address(struct sockaddr_storage *addr)
181
{
182
    if (addr->ss_family == AF_INET) {
183
        return IN_MULTICAST(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr));
184
    }
185
    if (addr->ss_family == AF_INET6) {
186
        return IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)addr)->sin6_addr);
187
    }
188

    
189
    return 0;
190
}
191

    
192
static int udp_socket_create(UDPContext *s, struct sockaddr_storage *addr, int *addr_len)
193
{
194
    int udp_fd = -1;
195
    struct addrinfo *res0 = NULL, *res = NULL;
196
    int family = AF_UNSPEC;
197

    
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);
201
    if (res0 == 0)
202
        goto fail;
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));
207
    }
208

    
209
    if (udp_fd < 0)
210
        goto fail;
211

    
212
    memcpy(addr, res->ai_addr, res->ai_addrlen);
213
    *addr_len = res->ai_addrlen;
214

    
215
    freeaddrinfo(res0);
216

    
217
    return udp_fd;
218

    
219
 fail:
220
    if (udp_fd >= 0)
221
        closesocket(udp_fd);
222
    if(res0)
223
        freeaddrinfo(res0);
224
    return -1;
225
}
226

    
227
static int udp_port(struct sockaddr_storage *addr, int addr_len)
228
{
229
    char sbuf[sizeof(int)*3+1];
230

    
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));
233
        return -1;
234
    }
235

    
236
    return strtol(sbuf, NULL, 10);
237
}
238

    
239
#else
240

    
241
static int udp_set_url(struct sockaddr_in *addr, const char *hostname, int port)
242
{
243
    /* set the destination address */
244
    if (resolve_host(&addr->sin_addr, hostname) < 0)
245
        return AVERROR(EIO);
246
    addr->sin_family = AF_INET;
247
    addr->sin_port = htons(port);
248

    
249
    return sizeof(struct sockaddr_in);
250
}
251

    
252
static int is_multicast_address(struct sockaddr_in *addr)
253
{
254
    return IN_MULTICAST(ntohl(addr->sin_addr.s_addr));
255
}
256

    
257
static int udp_socket_create(UDPContext *s, struct sockaddr_in *addr, int *addr_len)
258
{
259
    int fd;
260

    
261
    fd = socket(AF_INET, SOCK_DGRAM, 0);
262
    if (fd < 0)
263
        return -1;
264

    
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);
269

    
270
    return fd;
271
}
272

    
273
static int udp_port(struct sockaddr_in *addr, int len)
274
{
275
    return ntohs(addr->sin_port);
276
}
277
#endif /* CONFIG_IPV6 */
278

    
279

    
280
/**
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.
284
 *
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
290
 *
291
 * @param s1 media file context
292
 * @param uri of the remote server
293
 * @return zero if no error.
294
 */
295
int udp_set_remote_url(URLContext *h, const char *uri)
296
{
297
    UDPContext *s = h->priv_data;
298
    char hostname[256];
299
    int port;
300

    
301
    url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
302

    
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) {
306
        return AVERROR(EIO);
307
    }
308
    s->is_multicast = is_multicast_address(&s->dest_addr);
309

    
310
    return 0;
311
}
312

    
313
/**
314
 * Return the local port used by the UDP connexion
315
 * @param s1 media file context
316
 * @return the local port number
317
 */
318
int udp_get_local_port(URLContext *h)
319
{
320
    UDPContext *s = h->priv_data;
321
    return s->local_port;
322
}
323

    
324
/**
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
328
 */
329
int udp_get_file_handle(URLContext *h)
330
{
331
    UDPContext *s = h->priv_data;
332
    return s->udp_fd;
333
}
334

    
335
/* put it in UDP context */
336
/* return non zero if error */
337
static int udp_open(URLContext *h, const char *uri, int flags)
338
{
339
    char hostname[1024];
340
    int port, udp_fd = -1, tmp, bind_ret = -1;
341
    UDPContext *s = NULL;
342
    int is_output;
343
    const char *p;
344
    char buf[256];
345
#ifndef CONFIG_IPV6
346
    struct sockaddr_in my_addr;
347
#else
348
    struct sockaddr_storage my_addr;
349
#endif
350
    int len;
351

    
352
    h->is_streamed = 1;
353
    h->max_packet_size = 1472;
354

    
355
    is_output = (flags & URL_WRONLY);
356

    
357
    if(!ff_network_init())
358
        return AVERROR(EIO);
359

    
360
    s = av_mallocz(sizeof(UDPContext));
361
    if (!s)
362
        return AVERROR(ENOMEM);
363

    
364
    h->priv_data = s;
365
    s->ttl = 16;
366
    s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE;
367

    
368
    p = strchr(uri, '?');
369
    if (p) {
370
        s->reuse_socket = find_info_tag(buf, sizeof(buf), "reuse", p);
371
        if (find_info_tag(buf, sizeof(buf), "ttl", p)) {
372
            s->ttl = strtol(buf, NULL, 10);
373
        }
374
        if (find_info_tag(buf, sizeof(buf), "localport", p)) {
375
            s->local_port = strtol(buf, NULL, 10);
376
        }
377
        if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
378
            h->max_packet_size = strtol(buf, NULL, 10);
379
        }
380
        if (find_info_tag(buf, sizeof(buf), "buffer_size", p)) {
381
            s->buffer_size = strtol(buf, NULL, 10);
382
        }
383
    }
384

    
385
    /* fill the dest addr */
386
    url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
387

    
388
    /* XXX: fix url_split */
389
    if (hostname[0] == '\0' || hostname[0] == '?') {
390
        /* only accepts null hostname if input */
391
        if (flags & URL_WRONLY)
392
            goto fail;
393
    } else {
394
        udp_set_remote_url(h, uri);
395
    }
396

    
397
    if (s->is_multicast && !(h->flags & URL_WRONLY))
398
        s->local_port = port;
399
    udp_fd = udp_socket_create(s, &my_addr, &len);
400
    if (udp_fd < 0)
401
        goto fail;
402

    
403
    if (s->reuse_socket)
404
        if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0)
405
            goto fail;
406

    
407
    /* the bind is needed to give a port to the socket now */
408
    /* if multicast, try the multicast address bind first */
409
    if (s->is_multicast && !(h->flags & URL_WRONLY)) {
410
        bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len);
411
    }
412
    /* bind to the local address if not multicast or if the multicast
413
     * bind failed */
414
    if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0)
415
        goto fail;
416

    
417
    len = sizeof(my_addr);
418
    getsockname(udp_fd, (struct sockaddr *)&my_addr, &len);
419
    s->local_port = udp_port(&my_addr, len);
420

    
421
    if (s->is_multicast) {
422
        if (h->flags & URL_WRONLY) {
423
            /* output */
424
            if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0)
425
                goto fail;
426
        } else {
427
            /* input */
428
            if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0)
429
                goto fail;
430
        }
431
    }
432

    
433
    if (is_output) {
434
        /* limit the tx buf size to limit latency */
435
        tmp = s->buffer_size;
436
        if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) {
437
            av_log(NULL, AV_LOG_ERROR, "setsockopt(SO_SNDBUF): %s\n", strerror(errno));
438
            goto fail;
439
        }
440
    } else {
441
        /* set udp recv buffer size to the largest possible udp packet size to
442
         * avoid losing data on OSes that set this too low by default. */
443
        tmp = s->buffer_size;
444
        if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) {
445
            av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_RECVBUF): %s\n", strerror(errno));
446
        }
447
        /* make the socket non-blocking */
448
        ff_socket_nonblock(udp_fd, 1);
449
    }
450

    
451
    s->udp_fd = udp_fd;
452
    return 0;
453
 fail:
454
    if (udp_fd >= 0)
455
        closesocket(udp_fd);
456
    av_free(s);
457
    return AVERROR(EIO);
458
}
459

    
460
static int udp_read(URLContext *h, uint8_t *buf, int size)
461
{
462
    UDPContext *s = h->priv_data;
463
    int len;
464
    fd_set rfds;
465
    int ret;
466
    struct timeval tv;
467

    
468
    for(;;) {
469
        if (url_interrupt_cb())
470
            return AVERROR(EINTR);
471
        FD_ZERO(&rfds);
472
        FD_SET(s->udp_fd, &rfds);
473
        tv.tv_sec = 0;
474
        tv.tv_usec = 100 * 1000;
475
        ret = select(s->udp_fd + 1, &rfds, NULL, NULL, &tv);
476
        if (ret < 0)
477
            return AVERROR(EIO);
478
        if (!(ret > 0 && FD_ISSET(s->udp_fd, &rfds)))
479
            continue;
480
        len = recv(s->udp_fd, buf, size, 0);
481
        if (len < 0) {
482
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
483
                ff_neterrno() != FF_NETERROR(EINTR))
484
                return AVERROR(EIO);
485
        } else {
486
            break;
487
        }
488
    }
489
    return len;
490
}
491

    
492
static int udp_write(URLContext *h, uint8_t *buf, int size)
493
{
494
    UDPContext *s = h->priv_data;
495
    int ret;
496

    
497
    for(;;) {
498
        ret = sendto (s->udp_fd, buf, size, 0,
499
                      (struct sockaddr *) &s->dest_addr,
500
                      s->dest_addr_len);
501
        if (ret < 0) {
502
            if (ff_neterrno() != FF_NETERROR(EINTR) &&
503
                ff_neterrno() != FF_NETERROR(EAGAIN))
504
                return AVERROR(EIO);
505
        } else {
506
            break;
507
        }
508
    }
509
    return size;
510
}
511

    
512
static int udp_close(URLContext *h)
513
{
514
    UDPContext *s = h->priv_data;
515

    
516
    if (s->is_multicast && !(h->flags & URL_WRONLY))
517
        udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr);
518
    closesocket(s->udp_fd);
519
    ff_network_close();
520
    av_free(s);
521
    return 0;
522
}
523

    
524
URLProtocol udp_protocol = {
525
    "udp",
526
    udp_open,
527
    udp_read,
528
    udp_write,
529
    NULL, /* seek */
530
    udp_close,
531
};