~ubuntu-branches/ubuntu/saucy/gst-libav1.0/saucy-proposed

« back to all changes in this revision

Viewing changes to gst-libs/ext/libav/libavformat/udp.c

  • Committer: Package Import Robot
  • Author(s): Sebastian Dröge
  • Date: 2013-07-30 09:00:15 UTC
  • mfrom: (1.1.16) (7.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20130730090015-sc1ou2yssu7q5w4e
Tags: 1.1.3-1
* New upstream development snapshot:
  + debian/control:
    - Build depend on GStreamer and gst-plugins-base >= 1.1.3.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
#include "avio_internal.h"
31
31
#include "libavutil/parseutils.h"
32
32
#include "libavutil/avstring.h"
33
 
#include <unistd.h>
34
33
#include "internal.h"
35
34
#include "network.h"
36
35
#include "os_support.h"
37
36
#include "url.h"
38
 
#include <sys/time.h>
39
37
 
40
38
#ifndef IPV6_ADD_MEMBERSHIP
41
39
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
57
55
#define UDP_TX_BUF_SIZE 32768
58
56
#define UDP_MAX_PKT_SIZE 65536
59
57
 
 
58
static void log_net_error(void *ctx, int level, const char* prefix)
 
59
{
 
60
    char errbuf[100];
 
61
    av_strerror(ff_neterrno(), errbuf, sizeof(errbuf));
 
62
    av_log(ctx, level, "%s: %s\n", prefix, errbuf);
 
63
}
 
64
 
60
65
static int udp_set_multicast_ttl(int sockfd, int mcastTTL,
61
66
                                 struct sockaddr *addr)
62
67
{
63
68
#ifdef IP_MULTICAST_TTL
64
69
    if (addr->sa_family == AF_INET) {
65
70
        if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &mcastTTL, sizeof(mcastTTL)) < 0) {
66
 
            av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_TTL): %s\n", strerror(errno));
 
71
            log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_TTL)");
67
72
            return -1;
68
73
        }
69
74
    }
71
76
#if defined(IPPROTO_IPV6) && defined(IPV6_MULTICAST_HOPS)
72
77
    if (addr->sa_family == AF_INET6) {
73
78
        if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastTTL, sizeof(mcastTTL)) < 0) {
74
 
            av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_HOPS): %s\n", strerror(errno));
 
79
            log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_HOPS)");
75
80
            return -1;
76
81
        }
77
82
    }
88
93
        mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
89
94
        mreq.imr_interface.s_addr= INADDR_ANY;
90
95
        if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
91
 
            av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno));
 
96
            log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP)");
92
97
            return -1;
93
98
        }
94
99
    }
100
105
        memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
101
106
        mreq6.ipv6mr_interface= 0;
102
107
        if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
103
 
            av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP): %s\n", strerror(errno));
 
108
            log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP)");
104
109
            return -1;
105
110
        }
106
111
    }
117
122
        mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
118
123
        mreq.imr_interface.s_addr= INADDR_ANY;
119
124
        if (setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
120
 
            av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_DROP_MEMBERSHIP): %s\n", strerror(errno));
 
125
            log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_DROP_MEMBERSHIP)");
121
126
            return -1;
122
127
        }
123
128
    }
129
134
        memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
130
135
        mreq6.ipv6mr_interface= 0;
131
136
        if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
132
 
            av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP): %s\n", strerror(errno));
 
137
            log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP)");
133
138
            return -1;
134
139
        }
135
140
    }
140
145
static struct addrinfo* udp_resolve_host(const char *hostname, int port,
141
146
                                         int type, int family, int flags)
142
147
{
143
 
    struct addrinfo hints, *res = 0;
 
148
    struct addrinfo hints = { 0 }, *res = 0;
144
149
    int error;
145
150
    char sport[16];
146
151
    const char *node = 0, *service = "0";
152
157
    if ((hostname) && (hostname[0] != '\0') && (hostname[0] != '?')) {
153
158
        node = hostname;
154
159
    }
155
 
    memset(&hints, 0, sizeof(hints));
156
160
    hints.ai_socktype = type;
157
161
    hints.ai_family   = family;
158
162
    hints.ai_flags = flags;
164
168
    return res;
165
169
}
166
170
 
 
171
static int udp_set_multicast_sources(int sockfd, struct sockaddr *addr,
 
172
                                     int addr_len, char **sources,
 
173
                                     int nb_sources, int include)
 
174
{
 
175
#if HAVE_STRUCT_GROUP_SOURCE_REQ && defined(MCAST_BLOCK_SOURCE) && !defined(_WIN32)
 
176
    /* These ones are available in the microsoft SDK, but don't seem to work
 
177
     * as on linux, so just prefer the v4-only approach there for now. */
 
178
    int i;
 
179
    for (i = 0; i < nb_sources; i++) {
 
180
        struct group_source_req mreqs;
 
181
        int level = addr->sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
 
182
        struct addrinfo *sourceaddr = udp_resolve_host(sources[i], 0,
 
183
                                                       SOCK_DGRAM, AF_UNSPEC,
 
184
                                                       AI_NUMERICHOST);
 
185
        if (!sourceaddr)
 
186
            return AVERROR(ENOENT);
 
187
 
 
188
        mreqs.gsr_interface = 0;
 
189
        memcpy(&mreqs.gsr_group, addr, addr_len);
 
190
        memcpy(&mreqs.gsr_source, sourceaddr->ai_addr, sourceaddr->ai_addrlen);
 
191
        freeaddrinfo(sourceaddr);
 
192
 
 
193
        if (setsockopt(sockfd, level,
 
194
                       include ? MCAST_JOIN_SOURCE_GROUP : MCAST_BLOCK_SOURCE,
 
195
                       (const void *)&mreqs, sizeof(mreqs)) < 0) {
 
196
            if (include)
 
197
                log_net_error(NULL, AV_LOG_ERROR, "setsockopt(MCAST_JOIN_SOURCE_GROUP)");
 
198
            else
 
199
                log_net_error(NULL, AV_LOG_ERROR, "setsockopt(MCAST_BLOCK_SOURCE)");
 
200
            return ff_neterrno();
 
201
        }
 
202
    }
 
203
#elif HAVE_STRUCT_IP_MREQ_SOURCE && defined(IP_BLOCK_SOURCE)
 
204
    int i;
 
205
    if (addr->sa_family != AF_INET) {
 
206
        av_log(NULL, AV_LOG_ERROR,
 
207
               "Setting multicast sources only supported for IPv4\n");
 
208
        return AVERROR(EINVAL);
 
209
    }
 
210
    for (i = 0; i < nb_sources; i++) {
 
211
        struct ip_mreq_source mreqs;
 
212
        struct addrinfo *sourceaddr = udp_resolve_host(sources[i], 0,
 
213
                                                       SOCK_DGRAM, AF_UNSPEC,
 
214
                                                       AI_NUMERICHOST);
 
215
        if (!sourceaddr)
 
216
            return AVERROR(ENOENT);
 
217
        if (sourceaddr->ai_addr->sa_family != AF_INET) {
 
218
            freeaddrinfo(sourceaddr);
 
219
            av_log(NULL, AV_LOG_ERROR, "%s is of incorrect protocol family\n",
 
220
                   sources[i]);
 
221
            return AVERROR(EINVAL);
 
222
        }
 
223
 
 
224
        mreqs.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
 
225
        mreqs.imr_interface.s_addr = INADDR_ANY;
 
226
        mreqs.imr_sourceaddr.s_addr = ((struct sockaddr_in *)sourceaddr->ai_addr)->sin_addr.s_addr;
 
227
        freeaddrinfo(sourceaddr);
 
228
 
 
229
        if (setsockopt(sockfd, IPPROTO_IP,
 
230
                       include ? IP_ADD_SOURCE_MEMBERSHIP : IP_BLOCK_SOURCE,
 
231
                       (const void *)&mreqs, sizeof(mreqs)) < 0) {
 
232
            if (include)
 
233
                log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_SOURCE_MEMBERSHIP)");
 
234
            else
 
235
                log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_BLOCK_SOURCE)");
 
236
            return ff_neterrno();
 
237
        }
 
238
    }
 
239
#else
 
240
    return AVERROR(ENOSYS);
 
241
#endif
 
242
    return 0;
 
243
}
167
244
static int udp_set_url(struct sockaddr_storage *addr,
168
245
                       const char *hostname, int port)
169
246
{
180
257
}
181
258
 
182
259
static int udp_socket_create(UDPContext *s, struct sockaddr_storage *addr,
183
 
                             int *addr_len, const char *localaddr)
 
260
                             socklen_t *addr_len, const char *localaddr)
184
261
{
185
262
    int udp_fd = -1;
186
263
    struct addrinfo *res0 = NULL, *res = NULL;
194
271
        goto fail;
195
272
    for (res = res0; res; res=res->ai_next) {
196
273
        udp_fd = socket(res->ai_family, SOCK_DGRAM, 0);
197
 
        if (udp_fd > 0) break;
198
 
        av_log(NULL, AV_LOG_ERROR, "socket: %s\n", strerror(errno));
 
274
        if (udp_fd != -1) break;
 
275
        log_net_error(NULL, AV_LOG_ERROR, "socket");
199
276
    }
200
277
 
201
278
    if (udp_fd < 0)
219
296
static int udp_port(struct sockaddr_storage *addr, int addr_len)
220
297
{
221
298
    char sbuf[sizeof(int)*3+1];
 
299
    int error;
222
300
 
223
 
    if (getnameinfo((struct sockaddr *)addr, addr_len, NULL, 0,  sbuf, sizeof(sbuf), NI_NUMERICSERV) != 0) {
224
 
        av_log(NULL, AV_LOG_ERROR, "getnameinfo: %s\n", strerror(errno));
 
301
    if ((error = getnameinfo((struct sockaddr *)addr, addr_len, NULL, 0,  sbuf, sizeof(sbuf), NI_NUMERICSERV)) != 0) {
 
302
        av_log(NULL, AV_LOG_ERROR, "getnameinfo: %s\n", gai_strerror(error));
225
303
        return -1;
226
304
    }
227
305
 
268
346
                if (connect(s->udp_fd, (struct sockaddr *) &s->dest_addr,
269
347
                            s->dest_addr_len)) {
270
348
                    s->is_connected = 0;
271
 
                    av_log(h, AV_LOG_ERROR, "connect: %s\n", strerror(errno));
 
349
                    log_net_error(h, AV_LOG_ERROR, "connect");
272
350
                    return AVERROR(EIO);
273
351
                }
274
352
            }
311
389
    const char *p;
312
390
    char buf[256];
313
391
    struct sockaddr_storage my_addr;
314
 
    int len;
 
392
    socklen_t len;
315
393
    int reuse_specified = 0;
 
394
    int i, include = 0, num_sources = 0;
 
395
    char *sources[32];
316
396
 
317
397
    h->is_streamed = 1;
318
398
    h->max_packet_size = 1472;
350
430
        if (av_find_info_tag(buf, sizeof(buf), "localaddr", p)) {
351
431
            av_strlcpy(localaddr, buf, sizeof(localaddr));
352
432
        }
 
433
        if (av_find_info_tag(buf, sizeof(buf), "sources", p))
 
434
            include = 1;
 
435
        if (include || av_find_info_tag(buf, sizeof(buf), "block", p)) {
 
436
            char *source_start;
 
437
 
 
438
            source_start = buf;
 
439
            while (1) {
 
440
                char *next = strchr(source_start, ',');
 
441
                if (next)
 
442
                    *next = '\0';
 
443
                sources[num_sources] = av_strdup(source_start);
 
444
                if (!sources[num_sources])
 
445
                    goto fail;
 
446
                source_start = next + 1;
 
447
                num_sources++;
 
448
                if (num_sources >= FF_ARRAY_ELEMS(sources) || !next)
 
449
                    break;
 
450
            }
 
451
        }
353
452
    }
354
453
 
355
454
    /* fill the dest addr */
380
479
            goto fail;
381
480
    }
382
481
 
383
 
    /* the bind is needed to give a port to the socket now */
384
 
    /* if multicast, try the multicast address bind first */
385
 
    if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) {
 
482
    /* If multicast, try binding the multicast address first, to avoid
 
483
     * receiving UDP packets from other sources aimed at the same UDP
 
484
     * port. This fails on windows. This makes sending to the same address
 
485
     * using sendto() fail, so only do it if we're opened in read-only mode. */
 
486
    if (s->is_multicast && !(h->flags & AVIO_FLAG_WRITE)) {
386
487
        bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len);
387
488
    }
388
489
    /* bind to the local address if not multicast or if the multicast
389
490
     * bind failed */
390
 
    if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0)
 
491
    /* the bind is needed to give a port to the socket now */
 
492
    if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) {
 
493
        log_net_error(h, AV_LOG_ERROR, "bind failed");
391
494
        goto fail;
 
495
    }
392
496
 
393
497
    len = sizeof(my_addr);
394
498
    getsockname(udp_fd, (struct sockaddr *)&my_addr, &len);
395
499
    s->local_port = udp_port(&my_addr, len);
396
500
 
397
501
    if (s->is_multicast) {
398
 
        if (!(h->flags & AVIO_FLAG_READ)) {
 
502
        if (h->flags & AVIO_FLAG_WRITE) {
399
503
            /* output */
400
504
            if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0)
401
505
                goto fail;
402
 
        } else {
 
506
        }
 
507
        if (h->flags & AVIO_FLAG_READ) {
403
508
            /* input */
404
 
            if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0)
 
509
            if (num_sources == 0 || !include) {
 
510
                if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0)
 
511
                    goto fail;
 
512
 
 
513
                if (num_sources) {
 
514
                    if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, sources, num_sources, 0) < 0)
 
515
                        goto fail;
 
516
                }
 
517
            } else if (include && num_sources) {
 
518
                if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, sources, num_sources, 1) < 0)
 
519
                    goto fail;
 
520
            } else {
 
521
                av_log(NULL, AV_LOG_ERROR, "invalid udp settings: inclusive multicast but no sources given\n");
405
522
                goto fail;
 
523
            }
406
524
        }
407
525
    }
408
526
 
410
528
        /* limit the tx buf size to limit latency */
411
529
        tmp = s->buffer_size;
412
530
        if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) {
413
 
            av_log(h, AV_LOG_ERROR, "setsockopt(SO_SNDBUF): %s\n", strerror(errno));
 
531
            log_net_error(h, AV_LOG_ERROR, "setsockopt(SO_SNDBUF)");
414
532
            goto fail;
415
533
        }
416
534
    } else {
418
536
         * avoid losing data on OSes that set this too low by default. */
419
537
        tmp = s->buffer_size;
420
538
        if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) {
421
 
            av_log(h, AV_LOG_WARNING, "setsockopt(SO_RECVBUF): %s\n", strerror(errno));
 
539
            log_net_error(h, AV_LOG_WARNING, "setsockopt(SO_RECVBUF)");
422
540
        }
423
541
        /* make the socket non-blocking */
424
542
        ff_socket_nonblock(udp_fd, 1);
425
543
    }
426
544
    if (s->is_connected) {
427
545
        if (connect(udp_fd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len)) {
428
 
            av_log(h, AV_LOG_ERROR, "connect: %s\n", strerror(errno));
 
546
            log_net_error(h, AV_LOG_ERROR, "connect");
429
547
            goto fail;
430
548
        }
431
549
    }
432
550
 
 
551
    for (i = 0; i < num_sources; i++)
 
552
        av_free(sources[i]);
 
553
 
433
554
    s->udp_fd = udp_fd;
434
555
    return 0;
435
556
 fail:
436
557
    if (udp_fd >= 0)
437
558
        closesocket(udp_fd);
 
559
    for (i = 0; i < num_sources; i++)
 
560
        av_free(sources[i]);
438
561
    return AVERROR(EIO);
439
562
}
440
563