~diresu/blender/blender-command-port

« back to all changes in this revision

Viewing changes to extern/ffmpeg/libavformat/udp.c

  • Committer: theeth
  • Date: 2008-10-14 16:52:04 UTC
  • Revision ID: vcs-imports@canonical.com-20081014165204-r32w2gm6s0osvdhn
copy back trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include "avformat.h"
 
22
#include <unistd.h>
 
23
#include "network.h"
 
24
 
 
25
#ifndef IPV6_ADD_MEMBERSHIP
 
26
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
 
27
#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
 
28
#endif
 
29
 
 
30
typedef struct {
 
31
    int udp_fd;
 
32
    int ttl;
 
33
    int is_multicast;
 
34
    int local_port;
 
35
    int reuse_socket;
 
36
#ifndef CONFIG_IPV6
 
37
    struct ip_mreq mreq;
 
38
    struct sockaddr_in dest_addr;
 
39
#else
 
40
    struct sockaddr_storage dest_addr;
 
41
    size_t dest_addr_len;
 
42
#endif
 
43
} UDPContext;
 
44
 
 
45
#define UDP_TX_BUF_SIZE 32768
 
46
#define UDP_MAX_PKT_SIZE 65536
 
47
 
 
48
#ifdef CONFIG_IPV6
 
49
 
 
50
static int udp_ipv6_set_multicast_ttl(int sockfd, int mcastTTL, struct sockaddr *addr) {
 
51
    if (addr->sa_family == AF_INET) {
 
52
        if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &mcastTTL, sizeof(mcastTTL)) < 0) {
 
53
            perror("setsockopt(IP_MULTICAST_TTL)");
 
54
            return -1;
 
55
        }
 
56
    }
 
57
    if (addr->sa_family == AF_INET6) {
 
58
        if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastTTL, sizeof(mcastTTL)) < 0) {
 
59
            perror("setsockopt(IPV6_MULTICAST_HOPS)");
 
60
            return -1;
 
61
        }
 
62
    }
 
63
    return 0;
 
64
}
 
65
 
 
66
static int udp_ipv6_join_multicast_group(int sockfd, struct sockaddr *addr) {
 
67
    struct ip_mreq   mreq;
 
68
    struct ipv6_mreq mreq6;
 
69
    if (addr->sa_family == AF_INET) {
 
70
        mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
 
71
        mreq.imr_interface.s_addr= INADDR_ANY;
 
72
        if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
 
73
            perror("setsockopt(IP_ADD_MEMBERSHIP)");
 
74
            return -1;
 
75
        }
 
76
    }
 
77
    if (addr->sa_family == AF_INET6) {
 
78
        memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
 
79
        mreq6.ipv6mr_interface= 0;
 
80
        if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
 
81
            perror("setsockopt(IPV6_ADD_MEMBERSHIP)");
 
82
            return -1;
 
83
        }
 
84
    }
 
85
    return 0;
 
86
}
 
87
 
 
88
static int udp_ipv6_leave_multicast_group(int sockfd, struct sockaddr *addr) {
 
89
    struct ip_mreq   mreq;
 
90
    struct ipv6_mreq mreq6;
 
91
    if (addr->sa_family == AF_INET) {
 
92
        mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
 
93
        mreq.imr_interface.s_addr= INADDR_ANY;
 
94
        if (setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
 
95
            perror("setsockopt(IP_DROP_MEMBERSHIP)");
 
96
            return -1;
 
97
        }
 
98
    }
 
99
    if (addr->sa_family == AF_INET6) {
 
100
        memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
 
101
        mreq6.ipv6mr_interface= 0;
 
102
        if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
 
103
            perror("setsockopt(IPV6_DROP_MEMBERSHIP)");
 
104
            return -1;
 
105
        }
 
106
    }
 
107
    return 0;
 
108
}
 
109
 
 
110
static struct addrinfo* udp_ipv6_resolve_host(const char *hostname, int port, int type, int family, int flags) {
 
111
    struct addrinfo hints, *res = 0;
 
112
    int error;
 
113
    char sport[16];
 
114
    const char *node = 0, *service = 0;
 
115
 
 
116
    if (port > 0) {
 
117
        snprintf(sport, sizeof(sport), "%d", port);
 
118
        service = sport;
 
119
    }
 
120
    if ((hostname) && (hostname[0] != '\0') && (hostname[0] != '?')) {
 
121
        node = hostname;
 
122
    }
 
123
    if ((node) || (service)) {
 
124
        memset(&hints, 0, sizeof(hints));
 
125
        hints.ai_socktype = type;
 
126
        hints.ai_family   = family;
 
127
        hints.ai_flags = flags;
 
128
        if ((error = getaddrinfo(node, service, &hints, &res))) {
 
129
            av_log(NULL, AV_LOG_ERROR, "udp_ipv6_resolve_host: %s\n", gai_strerror(error));
 
130
        }
 
131
    }
 
132
    return res;
 
133
}
 
134
 
 
135
static int udp_ipv6_set_remote_url(URLContext *h, const char *uri) {
 
136
    UDPContext *s = h->priv_data;
 
137
    char hostname[256];
 
138
    int port;
 
139
    struct addrinfo *res0;
 
140
    url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
 
141
    res0 = udp_ipv6_resolve_host(hostname, port, SOCK_DGRAM, AF_UNSPEC, 0);
 
142
    if (res0 == 0) return AVERROR(EIO);
 
143
    memcpy(&s->dest_addr, res0->ai_addr, res0->ai_addrlen);
 
144
    s->dest_addr_len = res0->ai_addrlen;
 
145
    freeaddrinfo(res0);
 
146
    return 0;
 
147
}
 
148
 
 
149
static int udp_ipv6_set_local(URLContext *h) {
 
150
    UDPContext *s = h->priv_data;
 
151
    int udp_fd = -1;
 
152
    struct sockaddr_storage clientaddr;
 
153
    socklen_t addrlen;
 
154
    char sbuf[NI_MAXSERV];
 
155
    char hbuf[NI_MAXHOST];
 
156
    struct addrinfo *res0 = NULL, *res = NULL;
 
157
 
 
158
    if (s->local_port != 0) {
 
159
        res0 = udp_ipv6_resolve_host(0, s->local_port, SOCK_DGRAM, AF_UNSPEC, AI_PASSIVE);
 
160
        if (res0 == 0)
 
161
            goto fail;
 
162
        for (res = res0; res; res=res->ai_next) {
 
163
            udp_fd = socket(res->ai_family, SOCK_DGRAM, 0);
 
164
            if (udp_fd > 0) break;
 
165
            perror("socket");
 
166
        }
 
167
    } else {
 
168
        udp_fd = socket(s->dest_addr.ss_family, SOCK_DGRAM, 0);
 
169
        if (udp_fd < 0)
 
170
            perror("socket");
 
171
    }
 
172
 
 
173
    if (udp_fd < 0)
 
174
        goto fail;
 
175
 
 
176
    if (s->local_port != 0) {
 
177
        if (bind(udp_fd, res0->ai_addr, res0->ai_addrlen) < 0) {
 
178
            perror("bind");
 
179
            goto fail;
 
180
        }
 
181
        freeaddrinfo(res0);
 
182
        res0 = NULL;
 
183
    }
 
184
 
 
185
    addrlen = sizeof(clientaddr);
 
186
    if (getsockname(udp_fd, (struct sockaddr *)&clientaddr, &addrlen) < 0) {
 
187
        perror("getsockname");
 
188
        goto fail;
 
189
    }
 
190
 
 
191
    if (getnameinfo((struct sockaddr *)&clientaddr, addrlen, hbuf, sizeof(hbuf),  sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
 
192
        perror("getnameinfo");
 
193
        goto fail;
 
194
    }
 
195
 
 
196
    s->local_port = strtol(sbuf, NULL, 10);
 
197
 
 
198
    return udp_fd;
 
199
 
 
200
 fail:
 
201
    if (udp_fd >= 0)
 
202
        closesocket(udp_fd);
 
203
    if(res0)
 
204
        freeaddrinfo(res0);
 
205
    return -1;
 
206
}
 
207
 
 
208
#endif /* CONFIG_IPV6 */
 
209
 
 
210
 
 
211
/**
 
212
 * If no filename is given to av_open_input_file because you want to
 
213
 * get the local port first, then you must call this function to set
 
214
 * the remote server address.
 
215
 *
 
216
 * url syntax: udp://host:port[?option=val...]
 
217
 * option: 'multicast=1' : enable multicast
 
218
 *         'ttl=n'       : set the ttl value (for multicast only)
 
219
 *         'localport=n' : set the local port
 
220
 *         'pkt_size=n'  : set max packet size
 
221
 *         'reuse=1'     : enable reusing the socket
 
222
 *
 
223
 * @param s1 media file context
 
224
 * @param uri of the remote server
 
225
 * @return zero if no error.
 
226
 */
 
227
int udp_set_remote_url(URLContext *h, const char *uri)
 
228
{
 
229
#ifdef CONFIG_IPV6
 
230
    return udp_ipv6_set_remote_url(h, uri);
 
231
#else
 
232
    UDPContext *s = h->priv_data;
 
233
    char hostname[256];
 
234
    int port;
 
235
 
 
236
    url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
 
237
 
 
238
    /* set the destination address */
 
239
    if (resolve_host(&s->dest_addr.sin_addr, hostname) < 0)
 
240
        return AVERROR(EIO);
 
241
    s->dest_addr.sin_family = AF_INET;
 
242
    s->dest_addr.sin_port = htons(port);
 
243
    return 0;
 
244
#endif
 
245
}
 
246
 
 
247
/**
 
248
 * Return the local port used by the UDP connexion
 
249
 * @param s1 media file context
 
250
 * @return the local port number
 
251
 */
 
252
int udp_get_local_port(URLContext *h)
 
253
{
 
254
    UDPContext *s = h->priv_data;
 
255
    return s->local_port;
 
256
}
 
257
 
 
258
/**
 
259
 * Return the udp file handle for select() usage to wait for several RTP
 
260
 * streams at the same time.
 
261
 * @param h media file context
 
262
 */
 
263
int udp_get_file_handle(URLContext *h)
 
264
{
 
265
    UDPContext *s = h->priv_data;
 
266
    return s->udp_fd;
 
267
}
 
268
 
 
269
/* put it in UDP context */
 
270
/* return non zero if error */
 
271
static int udp_open(URLContext *h, const char *uri, int flags)
 
272
{
 
273
    char hostname[1024];
 
274
    int port, udp_fd = -1, tmp;
 
275
    UDPContext *s = NULL;
 
276
    int is_output;
 
277
    const char *p;
 
278
    char buf[256];
 
279
#ifndef CONFIG_IPV6
 
280
    struct sockaddr_in my_addr, my_addr1;
 
281
    int len;
 
282
#endif
 
283
 
 
284
    h->is_streamed = 1;
 
285
    h->max_packet_size = 1472;
 
286
 
 
287
    is_output = (flags & URL_WRONLY);
 
288
 
 
289
    s = av_malloc(sizeof(UDPContext));
 
290
    if (!s)
 
291
        return AVERROR(ENOMEM);
 
292
 
 
293
    h->priv_data = s;
 
294
    s->ttl = 16;
 
295
    s->is_multicast = 0;
 
296
    s->local_port = 0;
 
297
    s->reuse_socket = 0;
 
298
    p = strchr(uri, '?');
 
299
    if (p) {
 
300
        s->is_multicast = find_info_tag(buf, sizeof(buf), "multicast", p);
 
301
        s->reuse_socket = find_info_tag(buf, sizeof(buf), "reuse", p);
 
302
        if (find_info_tag(buf, sizeof(buf), "ttl", p)) {
 
303
            s->ttl = strtol(buf, NULL, 10);
 
304
        }
 
305
        if (find_info_tag(buf, sizeof(buf), "localport", p)) {
 
306
            s->local_port = strtol(buf, NULL, 10);
 
307
        }
 
308
        if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
 
309
            h->max_packet_size = strtol(buf, NULL, 10);
 
310
        }
 
311
    }
 
312
 
 
313
    /* fill the dest addr */
 
314
    url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
 
315
 
 
316
    /* XXX: fix url_split */
 
317
    if (hostname[0] == '\0' || hostname[0] == '?') {
 
318
        /* only accepts null hostname if input */
 
319
        if (s->is_multicast || (flags & URL_WRONLY))
 
320
            goto fail;
 
321
    } else {
 
322
        udp_set_remote_url(h, uri);
 
323
    }
 
324
 
 
325
    if(!ff_network_init())
 
326
        return AVERROR(EIO);
 
327
 
 
328
#ifndef CONFIG_IPV6
 
329
    udp_fd = socket(AF_INET, SOCK_DGRAM, 0);
 
330
    if (udp_fd < 0)
 
331
        goto fail;
 
332
 
 
333
    my_addr.sin_family = AF_INET;
 
334
    my_addr.sin_addr.s_addr = htonl (INADDR_ANY);
 
335
    if (s->is_multicast && !(h->flags & URL_WRONLY)) {
 
336
        /* special case: the bind must be done on the multicast address port */
 
337
        my_addr.sin_port = s->dest_addr.sin_port;
 
338
    } else {
 
339
        my_addr.sin_port = htons(s->local_port);
 
340
    }
 
341
 
 
342
    if (s->reuse_socket)
 
343
        if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0)
 
344
            goto fail;
 
345
 
 
346
    /* the bind is needed to give a port to the socket now */
 
347
    if (bind(udp_fd,(struct sockaddr *)&my_addr, sizeof(my_addr)) < 0)
 
348
        goto fail;
 
349
 
 
350
    len = sizeof(my_addr1);
 
351
    getsockname(udp_fd, (struct sockaddr *)&my_addr1, &len);
 
352
    s->local_port = ntohs(my_addr1.sin_port);
 
353
 
 
354
#ifdef IP_MULTICAST_TTL
 
355
    if (s->is_multicast) {
 
356
        if (h->flags & URL_WRONLY) {
 
357
            /* output */
 
358
            if (setsockopt(udp_fd, IPPROTO_IP, IP_MULTICAST_TTL,
 
359
                           &s->ttl, sizeof(s->ttl)) < 0) {
 
360
                perror("IP_MULTICAST_TTL");
 
361
                goto fail;
 
362
            }
 
363
        } else {
 
364
            /* input */
 
365
            memset(&s->mreq, 0, sizeof(s->mreq));
 
366
            s->mreq.imr_multiaddr = s->dest_addr.sin_addr;
 
367
            s->mreq.imr_interface.s_addr = htonl (INADDR_ANY);
 
368
            if (setsockopt(udp_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
 
369
                           &s->mreq, sizeof(s->mreq)) < 0) {
 
370
                perror("rtp: IP_ADD_MEMBERSHIP");
 
371
                goto fail;
 
372
            }
 
373
        }
 
374
    }
 
375
#endif
 
376
#else
 
377
    if (s->is_multicast && !(h->flags & URL_WRONLY))
 
378
        s->local_port = port;
 
379
    udp_fd = udp_ipv6_set_local(h);
 
380
    if (udp_fd < 0)
 
381
        goto fail;
 
382
    if (s->is_multicast) {
 
383
        if (h->flags & URL_WRONLY) {
 
384
            if (udp_ipv6_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0)
 
385
                goto fail;
 
386
        } else {
 
387
            if (udp_ipv6_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0)
 
388
                goto fail;
 
389
        }
 
390
    }
 
391
#endif /* CONFIG_IPV6 */
 
392
 
 
393
    if (is_output) {
 
394
        /* limit the tx buf size to limit latency */
 
395
        tmp = UDP_TX_BUF_SIZE;
 
396
        if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) {
 
397
            perror("setsockopt sndbuf");
 
398
            goto fail;
 
399
        }
 
400
    } else {
 
401
        /* set udp recv buffer size to the largest possible udp packet size to
 
402
         * avoid losing data on OSes that set this too low by default. */
 
403
        tmp = UDP_MAX_PKT_SIZE;
 
404
        setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp));
 
405
    }
 
406
 
 
407
    s->udp_fd = udp_fd;
 
408
    return 0;
 
409
 fail:
 
410
    if (udp_fd >= 0)
 
411
        closesocket(udp_fd);
 
412
    av_free(s);
 
413
    return AVERROR(EIO);
 
414
}
 
415
 
 
416
static int udp_read(URLContext *h, uint8_t *buf, int size)
 
417
{
 
418
    UDPContext *s = h->priv_data;
 
419
#ifndef CONFIG_IPV6
 
420
    struct sockaddr_in from;
 
421
#else
 
422
    struct sockaddr_storage from;
 
423
#endif
 
424
    socklen_t from_len;
 
425
    int len;
 
426
 
 
427
    for(;;) {
 
428
        from_len = sizeof(from);
 
429
        len = recvfrom (s->udp_fd, buf, size, 0,
 
430
                        (struct sockaddr *)&from, &from_len);
 
431
        if (len < 0) {
 
432
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
 
433
                ff_neterrno() != FF_NETERROR(EINTR))
 
434
                return AVERROR(EIO);
 
435
        } else {
 
436
            break;
 
437
        }
 
438
    }
 
439
    return len;
 
440
}
 
441
 
 
442
static int udp_write(URLContext *h, uint8_t *buf, int size)
 
443
{
 
444
    UDPContext *s = h->priv_data;
 
445
    int ret;
 
446
 
 
447
    for(;;) {
 
448
        ret = sendto (s->udp_fd, buf, size, 0,
 
449
                      (struct sockaddr *) &s->dest_addr,
 
450
#ifndef CONFIG_IPV6
 
451
                      sizeof (s->dest_addr));
 
452
#else
 
453
                      s->dest_addr_len);
 
454
#endif
 
455
        if (ret < 0) {
 
456
            if (ff_neterrno() != FF_NETERROR(EINTR) &&
 
457
                ff_neterrno() != FF_NETERROR(EAGAIN))
 
458
                return AVERROR(EIO);
 
459
        } else {
 
460
            break;
 
461
        }
 
462
    }
 
463
    return size;
 
464
}
 
465
 
 
466
static int udp_close(URLContext *h)
 
467
{
 
468
    UDPContext *s = h->priv_data;
 
469
 
 
470
#ifndef CONFIG_IPV6
 
471
#ifdef IP_DROP_MEMBERSHIP
 
472
    if (s->is_multicast && !(h->flags & URL_WRONLY)) {
 
473
        if (setsockopt(s->udp_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
 
474
                       &s->mreq, sizeof(s->mreq)) < 0) {
 
475
            perror("IP_DROP_MEMBERSHIP");
 
476
        }
 
477
    }
 
478
#endif
 
479
#else
 
480
    if (s->is_multicast && !(h->flags & URL_WRONLY))
 
481
        udp_ipv6_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr);
 
482
#endif
 
483
    closesocket(s->udp_fd);
 
484
    ff_network_close();
 
485
    av_free(s);
 
486
    return 0;
 
487
}
 
488
 
 
489
URLProtocol udp_protocol = {
 
490
    "udp",
 
491
    udp_open,
 
492
    udp_read,
 
493
    udp_write,
 
494
    NULL, /* seek */
 
495
    udp_close,
 
496
};