Statistics
| Branch: | Revision:

ffmpeg / libavformat / udp.c @ 236bb1ab

History | View | Annotate | Download (14.1 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

    
33
#ifndef IPV6_ADD_MEMBERSHIP
34
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
35
#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
36
#endif
37
#ifndef IN_MULTICAST
38
#define IN_MULTICAST(a) ((((uint32_t)(a)) & 0xf0000000) == 0xe0000000)
39
#endif
40
#ifndef IN6_IS_ADDR_MULTICAST
41
#define IN6_IS_ADDR_MULTICAST(a) (((uint8_t *) (a))[0] == 0xff)
42
#endif
43

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

    
59
#define UDP_TX_BUF_SIZE 32768
60
#define UDP_MAX_PKT_SIZE 65536
61

    
62
static int udp_set_multicast_ttl(int sockfd, int mcastTTL, struct sockaddr *addr) {
63
#ifdef IP_MULTICAST_TTL
64
    if (addr->sa_family == AF_INET) {
65
        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));
67
            return -1;
68
        }
69
    }
70
#endif
71
#ifdef CONFIG_IPV6
72
    if (addr->sa_family == AF_INET6) {
73
        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));
75
            return -1;
76
        }
77
    }
78
#endif
79
    return 0;
80
}
81

    
82
static int udp_join_multicast_group(int sockfd, struct sockaddr *addr) {
83
#ifdef IP_ADD_MEMBERSHIP
84
    if (addr->sa_family == AF_INET) {
85
        struct ip_mreq mreq;
86

    
87
        mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
88
        mreq.imr_interface.s_addr= INADDR_ANY;
89
        if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
90
            av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno));
91
            return -1;
92
        }
93
    }
94
#endif
95
#ifdef CONFIG_IPV6
96
    if (addr->sa_family == AF_INET6) {
97
        struct ipv6_mreq mreq6;
98

    
99
        memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
100
        mreq6.ipv6mr_interface= 0;
101
        if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
102
            av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP): %s\n", strerror(errno));
103
            return -1;
104
        }
105
    }
106
#endif
107
    return 0;
108
}
109

    
110
static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr) {
111
#ifdef IP_DROP_MEMBERSHIP
112
    if (addr->sa_family == AF_INET) {
113
        struct ip_mreq mreq;
114

    
115
        mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
116
        mreq.imr_interface.s_addr= INADDR_ANY;
117
        if (setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
118
            av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_DROP_MEMBERSHIP): %s\n", strerror(errno));
119
            return -1;
120
        }
121
    }
122
#endif
123
#ifdef CONFIG_IPV6
124
    if (addr->sa_family == AF_INET6) {
125
        struct ipv6_mreq mreq6;
126

    
127
        memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
128
        mreq6.ipv6mr_interface= 0;
129
        if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
130
            av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP): %s\n", strerror(errno));
131
            return -1;
132
        }
133
    }
134
#endif
135
    return 0;
136
}
137

    
138
#ifdef CONFIG_IPV6
139
static struct addrinfo* udp_ipv6_resolve_host(const char *hostname, int port, int type, int family, int flags) {
140
    struct addrinfo hints, *res = 0;
141
    int error;
142
    char sport[16];
143
    const char *node = 0, *service = "0";
144

    
145
    if (port > 0) {
146
        snprintf(sport, sizeof(sport), "%d", port);
147
        service = sport;
148
    }
149
    if ((hostname) && (hostname[0] != '\0') && (hostname[0] != '?')) {
150
        node = hostname;
151
    }
152
    memset(&hints, 0, sizeof(hints));
153
    hints.ai_socktype = type;
154
    hints.ai_family   = family;
155
    hints.ai_flags = flags;
156
    if ((error = getaddrinfo(node, service, &hints, &res))) {
157
        av_log(NULL, AV_LOG_ERROR, "udp_ipv6_resolve_host: %s\n", gai_strerror(error));
158
    }
159

    
160
    return res;
161
}
162

    
163
static int udp_set_url(struct sockaddr_storage *addr, const char *hostname, int port) {
164
    struct addrinfo *res0;
165
    int addr_len;
166

    
167
    res0 = udp_ipv6_resolve_host(hostname, port, SOCK_DGRAM, AF_UNSPEC, 0);
168
    if (res0 == 0) return AVERROR(EIO);
169
    memcpy(addr, res0->ai_addr, res0->ai_addrlen);
170
    addr_len = res0->ai_addrlen;
171
    freeaddrinfo(res0);
172

    
173
    return addr_len;
174
}
175

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

    
185
    return 0;
186
}
187

    
188
static int udp_socket_create(UDPContext *s, struct sockaddr_storage *addr, int *addr_len)
189
{
190
    int udp_fd = -1;
191
    struct addrinfo *res0 = NULL, *res = NULL;
192
    int family = AF_UNSPEC;
193

    
194
    if (((struct sockaddr *) &s->dest_addr)->sa_family)
195
        family = ((struct sockaddr *) &s->dest_addr)->sa_family;
196
    res0 = udp_ipv6_resolve_host(0, s->local_port, SOCK_DGRAM, family, AI_PASSIVE);
197
    if (res0 == 0)
198
        goto fail;
199
    for (res = res0; res; res=res->ai_next) {
200
        udp_fd = socket(res->ai_family, SOCK_DGRAM, 0);
201
        if (udp_fd > 0) break;
202
        av_log(NULL, AV_LOG_ERROR, "socket: %s\n", strerror(errno));
203
    }
204

    
205
    if (udp_fd < 0)
206
        goto fail;
207

    
208
    memcpy(addr, res->ai_addr, res->ai_addrlen);
209
    *addr_len = res->ai_addrlen;
210

    
211
    freeaddrinfo(res0);
212

    
213
    return udp_fd;
214

    
215
 fail:
216
    if (udp_fd >= 0)
217
        closesocket(udp_fd);
218
    if(res0)
219
        freeaddrinfo(res0);
220
    return -1;
221
}
222

    
223
static int udp_port(struct sockaddr_storage *addr, int addr_len)
224
{
225
    char sbuf[sizeof(int)*3+1];
226

    
227
    if (getnameinfo((struct sockaddr *)addr, addr_len, NULL, 0,  sbuf, sizeof(sbuf), NI_NUMERICSERV) != 0) {
228
        av_log(NULL, AV_LOG_ERROR, "getnameinfo: %s\n", strerror(errno));
229
        return -1;
230
    }
231

    
232
    return strtol(sbuf, NULL, 10);
233
}
234

    
235
#else
236

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

    
245
    return sizeof(struct sockaddr_in);
246
}
247

    
248
static int is_multicast_address(struct sockaddr_in *addr)
249
{
250
    return IN_MULTICAST(ntohl(addr->sin_addr.s_addr));
251
}
252

    
253
static int udp_socket_create(UDPContext *s, struct sockaddr_in *addr, int *addr_len)
254
{
255
    int fd;
256

    
257
    fd = socket(AF_INET, SOCK_DGRAM, 0);
258
    if (fd < 0)
259
        return -1;
260

    
261
    addr->sin_family = AF_INET;
262
    addr->sin_addr.s_addr = htonl (INADDR_ANY);
263
    addr->sin_port = htons(s->local_port);
264
    *addr_len = sizeof(struct sockaddr_in);
265

    
266
    return fd;
267
}
268

    
269
static int udp_port(struct sockaddr_in *addr, int len)
270
{
271
    return ntohs(addr->sin_port);
272
}
273
#endif /* CONFIG_IPV6 */
274

    
275

    
276
/**
277
 * If no filename is given to av_open_input_file because you want to
278
 * get the local port first, then you must call this function to set
279
 * the remote server address.
280
 *
281
 * url syntax: udp://host:port[?option=val...]
282
 * option: 'ttl=n'       : set the ttl value (for multicast only)
283
 *         'localport=n' : set the local port
284
 *         'pkt_size=n'  : set max packet size
285
 *         'reuse=1'     : enable reusing the socket
286
 *
287
 * @param s1 media file context
288
 * @param uri of the remote server
289
 * @return zero if no error.
290
 */
291
int udp_set_remote_url(URLContext *h, const char *uri)
292
{
293
    UDPContext *s = h->priv_data;
294
    char hostname[256];
295
    int port;
296

    
297
    url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
298

    
299
    /* set the destination address */
300
    s->dest_addr_len = udp_set_url(&s->dest_addr, hostname, port);
301
    if (s->dest_addr_len < 0) {
302
        return AVERROR(EIO);
303
    }
304
    s->is_multicast = is_multicast_address(&s->dest_addr);
305

    
306
    return 0;
307
}
308

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

    
320
/**
321
 * Return the udp file handle for select() usage to wait for several RTP
322
 * streams at the same time.
323
 * @param h media file context
324
 */
325
int udp_get_file_handle(URLContext *h)
326
{
327
    UDPContext *s = h->priv_data;
328
    return s->udp_fd;
329
}
330

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

    
348
    h->is_streamed = 1;
349
    h->max_packet_size = 1472;
350

    
351
    is_output = (flags & URL_WRONLY);
352

    
353
    if(!ff_network_init())
354
        return AVERROR(EIO);
355

    
356
    s = av_mallocz(sizeof(UDPContext));
357
    if (!s)
358
        return AVERROR(ENOMEM);
359

    
360
    h->priv_data = s;
361
    s->ttl = 16;
362
    s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE;
363

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

    
381
    /* fill the dest addr */
382
    url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
383

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

    
393
    if (s->is_multicast && !(h->flags & URL_WRONLY))
394
        s->local_port = port;
395
    udp_fd = udp_socket_create(s, &my_addr, &len);
396
    if (udp_fd < 0)
397
        goto fail;
398

    
399
    if (s->reuse_socket)
400
        if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0)
401
            goto fail;
402

    
403
    /* the bind is needed to give a port to the socket now */
404
    if (bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0)
405
        goto fail;
406

    
407
    len = sizeof(my_addr);
408
    getsockname(udp_fd, (struct sockaddr *)&my_addr, &len);
409
    s->local_port = udp_port(&my_addr, len);
410

    
411
    if (s->is_multicast) {
412
        if (h->flags & URL_WRONLY) {
413
            /* output */
414
            if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0)
415
                goto fail;
416
        } else {
417
            /* input */
418
            if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0)
419
                goto fail;
420
        }
421
    }
422

    
423
    if (is_output) {
424
        /* limit the tx buf size to limit latency */
425
        tmp = s->buffer_size;
426
        if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) {
427
            av_log(NULL, AV_LOG_ERROR, "setsockopt(SO_SNDBUF): %s\n", strerror(errno));
428
            goto fail;
429
        }
430
    } else {
431
        /* set udp recv buffer size to the largest possible udp packet size to
432
         * avoid losing data on OSes that set this too low by default. */
433
        tmp = s->buffer_size;
434
        if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) {
435
            av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_RECVBUF): %s\n", strerror(errno));
436
        }
437
    }
438

    
439
    s->udp_fd = udp_fd;
440
    return 0;
441
 fail:
442
    if (udp_fd >= 0)
443
        closesocket(udp_fd);
444
    av_free(s);
445
    return AVERROR(EIO);
446
}
447

    
448
static int udp_read(URLContext *h, uint8_t *buf, int size)
449
{
450
    UDPContext *s = h->priv_data;
451
    int len;
452

    
453
    for(;;) {
454
        len = recv(s->udp_fd, buf, size, 0);
455
        if (len < 0) {
456
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
457
                ff_neterrno() != FF_NETERROR(EINTR))
458
                return AVERROR(EIO);
459
        } else {
460
            break;
461
        }
462
    }
463
    return len;
464
}
465

    
466
static int udp_write(URLContext *h, uint8_t *buf, int size)
467
{
468
    UDPContext *s = h->priv_data;
469
    int ret;
470

    
471
    for(;;) {
472
        ret = sendto (s->udp_fd, buf, size, 0,
473
                      (struct sockaddr *) &s->dest_addr,
474
                      s->dest_addr_len);
475
        if (ret < 0) {
476
            if (ff_neterrno() != FF_NETERROR(EINTR) &&
477
                ff_neterrno() != FF_NETERROR(EAGAIN))
478
                return AVERROR(EIO);
479
        } else {
480
            break;
481
        }
482
    }
483
    return size;
484
}
485

    
486
static int udp_close(URLContext *h)
487
{
488
    UDPContext *s = h->priv_data;
489

    
490
    if (s->is_multicast && !(h->flags & URL_WRONLY))
491
        udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr);
492
    closesocket(s->udp_fd);
493
    ff_network_close();
494
    av_free(s);
495
    return 0;
496
}
497

    
498
URLProtocol udp_protocol = {
499
    "udp",
500
    udp_open,
501
    udp_read,
502
    udp_write,
503
    NULL, /* seek */
504
    udp_close,
505
};