Statistics
| Branch: | Revision:

ffmpeg / libavformat / udp.c @ 470bce2b

History | View | Annotate | Download (15 KB)

1 de6d9b64 Fabrice Bellard
/*
2
 * UDP prototype streaming system
3 2d225591 Fabrice Bellard
 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard.
4 de6d9b64 Fabrice Bellard
 *
5 b78e7197 Diego Biurrun
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8 19720f15 Fabrice Bellard
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10 b78e7197 Diego Biurrun
 * version 2.1 of the License, or (at your option) any later version.
11 de6d9b64 Fabrice Bellard
 *
12 b78e7197 Diego Biurrun
 * FFmpeg is distributed in the hope that it will be useful,
13 de6d9b64 Fabrice Bellard
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 19720f15 Fabrice Bellard
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16 de6d9b64 Fabrice Bellard
 *
17 19720f15 Fabrice Bellard
 * You should have received a copy of the GNU Lesser General Public
18 b78e7197 Diego Biurrun
 * License along with FFmpeg; if not, write to the Free Software
19 5509bffa Diego Biurrun
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 de6d9b64 Fabrice Bellard
 */
21 3adfb377 Luca Barbato
22
/**
23
 * @file udp.c
24
 * UDP protocol
25
 */
26
27 a9e02947 Luca Abeni
#define _BSD_SOURCE     /* Needed for using struct ip_mreq with recent glibc */
28 8be1c656 Fabrice Bellard
#include "avformat.h"
29 de6d9b64 Fabrice Bellard
#include <unistd.h>
30 42572ef5 Ramiro Polla
#include "network.h"
31 087b3272 Luca Abeni
#include "os_support.h"
32 7d084299 Jindřich Makovička
#ifdef HAVE_SYS_SELECT_H
33
#include <sys/select.h>
34
#endif
35 c0a8f8d4 Dave Yeo
#include <sys/time.h>
36 de6d9b64 Fabrice Bellard
37 9c633e9a Alex Beregszaszi
#ifndef IPV6_ADD_MEMBERSHIP
38
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
39
#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
40
#endif
41 35b74c3d Luca Abeni
#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 9c633e9a Alex Beregszaszi
48 de6d9b64 Fabrice Bellard
typedef struct {
49 2d225591 Fabrice Bellard
    int udp_fd;
50
    int ttl;
51 236bb1ab Jindřich Makovička
    int buffer_size;
52 2d225591 Fabrice Bellard
    int is_multicast;
53
    int local_port;
54 34ecc397 Thijs
    int reuse_socket;
55 7a91333f Hans Zandbelt
#ifndef CONFIG_IPV6
56 2d225591 Fabrice Bellard
    struct sockaddr_in dest_addr;
57 7a91333f Hans Zandbelt
#else
58
    struct sockaddr_storage dest_addr;
59
#endif
60 397db8ac Luca Abeni
    int dest_addr_len;
61 de6d9b64 Fabrice Bellard
} UDPContext;
62
63
#define UDP_TX_BUF_SIZE 32768
64 f18cae4d Ramiro Polla
#define UDP_MAX_PKT_SIZE 65536
65 de6d9b64 Fabrice Bellard
66 9cdcb04f Luca Abeni
static int udp_set_multicast_ttl(int sockfd, int mcastTTL, struct sockaddr *addr) {
67 a8bde059 Luca Abeni
#ifdef IP_MULTICAST_TTL
68 7a91333f Hans Zandbelt
    if (addr->sa_family == AF_INET) {
69
        if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &mcastTTL, sizeof(mcastTTL)) < 0) {
70 086119b3 Luca Abeni
            av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_TTL): %s\n", strerror(errno));
71 7a91333f Hans Zandbelt
            return -1;
72
        }
73
    }
74 a8bde059 Luca Abeni
#endif
75
#ifdef CONFIG_IPV6
76 7a91333f Hans Zandbelt
    if (addr->sa_family == AF_INET6) {
77
        if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastTTL, sizeof(mcastTTL)) < 0) {
78 086119b3 Luca Abeni
            av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_HOPS): %s\n", strerror(errno));
79 7a91333f Hans Zandbelt
            return -1;
80
        }
81
    }
82 a8bde059 Luca Abeni
#endif
83 7a91333f Hans Zandbelt
    return 0;
84
}
85
86 9cdcb04f Luca Abeni
static int udp_join_multicast_group(int sockfd, struct sockaddr *addr) {
87 a8bde059 Luca Abeni
#ifdef IP_ADD_MEMBERSHIP
88 7a91333f Hans Zandbelt
    if (addr->sa_family == AF_INET) {
89 a8bde059 Luca Abeni
        struct ip_mreq mreq;
90
91 7a91333f Hans Zandbelt
        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 086119b3 Luca Abeni
            av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno));
95 7a91333f Hans Zandbelt
            return -1;
96
        }
97
    }
98 a8bde059 Luca Abeni
#endif
99
#ifdef CONFIG_IPV6
100 7a91333f Hans Zandbelt
    if (addr->sa_family == AF_INET6) {
101 a8bde059 Luca Abeni
        struct ipv6_mreq mreq6;
102
103 7a91333f Hans Zandbelt
        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 086119b3 Luca Abeni
            av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP): %s\n", strerror(errno));
107 7a91333f Hans Zandbelt
            return -1;
108
        }
109
    }
110 a8bde059 Luca Abeni
#endif
111 7a91333f Hans Zandbelt
    return 0;
112
}
113
114 9cdcb04f Luca Abeni
static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr) {
115 a8bde059 Luca Abeni
#ifdef IP_DROP_MEMBERSHIP
116 7a91333f Hans Zandbelt
    if (addr->sa_family == AF_INET) {
117 a8bde059 Luca Abeni
        struct ip_mreq mreq;
118
119 7a91333f Hans Zandbelt
        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 086119b3 Luca Abeni
            av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_DROP_MEMBERSHIP): %s\n", strerror(errno));
123 7a91333f Hans Zandbelt
            return -1;
124
        }
125
    }
126 a8bde059 Luca Abeni
#endif
127
#ifdef CONFIG_IPV6
128 7a91333f Hans Zandbelt
    if (addr->sa_family == AF_INET6) {
129 a8bde059 Luca Abeni
        struct ipv6_mreq mreq6;
130
131 7a91333f Hans Zandbelt
        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 086119b3 Luca Abeni
            av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP): %s\n", strerror(errno));
135 7a91333f Hans Zandbelt
            return -1;
136
        }
137
    }
138 a8bde059 Luca Abeni
#endif
139 7a91333f Hans Zandbelt
    return 0;
140
}
141
142 a8bde059 Luca Abeni
#ifdef CONFIG_IPV6
143 7b49ce2e Stefan Huehner
static struct addrinfo* udp_ipv6_resolve_host(const char *hostname, int port, int type, int family, int flags) {
144 7a91333f Hans Zandbelt
    struct addrinfo hints, *res = 0;
145
    int error;
146
    char sport[16];
147 d607861c Nicolas George
    const char *node = 0, *service = "0";
148 7a91333f Hans Zandbelt
149
    if (port > 0) {
150 2fc8ea24 Michael Niedermayer
        snprintf(sport, sizeof(sport), "%d", port);
151 7a91333f Hans Zandbelt
        service = sport;
152
    }
153
    if ((hostname) && (hostname[0] != '\0') && (hostname[0] != '?')) {
154
        node = hostname;
155
    }
156 7d8576c2 Luca Abeni
    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 7a91333f Hans Zandbelt
    return res;
165
}
166
167 d05cb726 Luca Abeni
static int udp_set_url(struct sockaddr_storage *addr, const char *hostname, int port) {
168 7a91333f Hans Zandbelt
    struct addrinfo *res0;
169 d05cb726 Luca Abeni
    int addr_len;
170
171 7a91333f Hans Zandbelt
    res0 = udp_ipv6_resolve_host(hostname, port, SOCK_DGRAM, AF_UNSPEC, 0);
172 6f3e0b21 Panagiotis Issaris
    if (res0 == 0) return AVERROR(EIO);
173 d05cb726 Luca Abeni
    memcpy(addr, res0->ai_addr, res0->ai_addrlen);
174
    addr_len = res0->ai_addrlen;
175 7a91333f Hans Zandbelt
    freeaddrinfo(res0);
176 d05cb726 Luca Abeni
177
    return addr_len;
178 7a91333f Hans Zandbelt
}
179
180 35b74c3d Luca Abeni
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 aa519c47 Luca Abeni
static int udp_socket_create(UDPContext *s, struct sockaddr_storage *addr, int *addr_len)
193
{
194 7a91333f Hans Zandbelt
    int udp_fd = -1;
195 276358c1 Hans Zandbelt
    struct addrinfo *res0 = NULL, *res = NULL;
196 51844e6c Ronald S. Bultje
    int family = AF_UNSPEC;
197 115329f1 Diego Biurrun
198 51844e6c Ronald S. Bultje
    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 7d8576c2 Luca Abeni
    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 086119b3 Luca Abeni
        av_log(NULL, AV_LOG_ERROR, "socket: %s\n", strerror(errno));
207 7d8576c2 Luca Abeni
    }
208 276358c1 Hans Zandbelt
209
    if (udp_fd < 0)
210 7a91333f Hans Zandbelt
        goto fail;
211 115329f1 Diego Biurrun
212 aa519c47 Luca Abeni
    memcpy(addr, res->ai_addr, res->ai_addrlen);
213
    *addr_len = res->ai_addrlen;
214 7a91333f Hans Zandbelt
215 aa519c47 Luca Abeni
    freeaddrinfo(res0);
216 115329f1 Diego Biurrun
217 7a91333f Hans Zandbelt
    return udp_fd;
218 115329f1 Diego Biurrun
219 7a91333f Hans Zandbelt
 fail:
220
    if (udp_fd >= 0)
221
        closesocket(udp_fd);
222 88730be6 Måns Rullgård
    if(res0)
223
        freeaddrinfo(res0);
224 7a91333f Hans Zandbelt
    return -1;
225
}
226
227 aa519c47 Luca Abeni
static int udp_port(struct sockaddr_storage *addr, int addr_len)
228
{
229 03c09e43 D Richard Felker III
    char sbuf[sizeof(int)*3+1];
230 aa519c47 Luca Abeni
231 03c09e43 D Richard Felker III
    if (getnameinfo((struct sockaddr *)addr, addr_len, NULL, 0,  sbuf, sizeof(sbuf), NI_NUMERICSERV) != 0) {
232 086119b3 Luca Abeni
        av_log(NULL, AV_LOG_ERROR, "getnameinfo: %s\n", strerror(errno));
233 aa519c47 Luca Abeni
        return -1;
234
    }
235
236
    return strtol(sbuf, NULL, 10);
237
}
238
239 d05cb726 Luca Abeni
#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 35b74c3d Luca Abeni
static int is_multicast_address(struct sockaddr_in *addr)
253
{
254
    return IN_MULTICAST(ntohl(addr->sin_addr.s_addr));
255
}
256
257 aa519c47 Luca Abeni
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 0a4f20c6 Diego Biurrun
#endif /* CONFIG_IPV6 */
278 7a91333f Hans Zandbelt
279
280 2d225591 Fabrice Bellard
/**
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 35b74c3d Luca Abeni
 * option: 'ttl=n'       : set the ttl value (for multicast only)
287 2d225591 Fabrice Bellard
 *         'localport=n' : set the local port
288 9899efb4 Max Krasnyansky
 *         'pkt_size=n'  : set max packet size
289 34ecc397 Thijs
 *         'reuse=1'     : enable reusing the socket
290 2d225591 Fabrice Bellard
 *
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 115329f1 Diego Biurrun
301 6ba5cbc6 Petr Doubek
    url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
302 de6d9b64 Fabrice Bellard
303 2d225591 Fabrice Bellard
    /* set the destination address */
304 d05cb726 Luca Abeni
    s->dest_addr_len = udp_set_url(&s->dest_addr, hostname, port);
305
    if (s->dest_addr_len < 0) {
306 6f3e0b21 Panagiotis Issaris
        return AVERROR(EIO);
307 d05cb726 Luca Abeni
    }
308 35b74c3d Luca Abeni
    s->is_multicast = is_multicast_address(&s->dest_addr);
309 d05cb726 Luca Abeni
310 2d225591 Fabrice Bellard
    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 de6d9b64 Fabrice Bellard
/* return non zero if error */
337
static int udp_open(URLContext *h, const char *uri, int flags)
338
{
339
    char hostname[1024];
340 36b53281 Jindřich Makovička
    int port, udp_fd = -1, tmp, bind_ret = -1;
341 2d225591 Fabrice Bellard
    UDPContext *s = NULL;
342 88730be6 Måns Rullgård
    int is_output;
343 2d225591 Fabrice Bellard
    const char *p;
344
    char buf[256];
345 88730be6 Måns Rullgård
#ifndef CONFIG_IPV6
346 d4936869 Luca Abeni
    struct sockaddr_in my_addr;
347 aa519c47 Luca Abeni
#else
348
    struct sockaddr_storage my_addr;
349 88730be6 Måns Rullgård
#endif
350 aa519c47 Luca Abeni
    int len;
351 de6d9b64 Fabrice Bellard
352
    h->is_streamed = 1;
353 9899efb4 Max Krasnyansky
    h->max_packet_size = 1472;
354 de6d9b64 Fabrice Bellard
355 2d225591 Fabrice Bellard
    is_output = (flags & URL_WRONLY);
356 115329f1 Diego Biurrun
357 e6c13819 Ronald S. Bultje
    if(!ff_network_init())
358
        return AVERROR(EIO);
359
360 51844e6c Ronald S. Bultje
    s = av_mallocz(sizeof(UDPContext));
361 2d225591 Fabrice Bellard
    if (!s)
362 8fa36ae0 François Revol
        return AVERROR(ENOMEM);
363 2d225591 Fabrice Bellard
364
    h->priv_data = s;
365
    s->ttl = 16;
366 236bb1ab Jindřich Makovička
    s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE;
367
368 2d225591 Fabrice Bellard
    p = strchr(uri, '?');
369
    if (p) {
370 34ecc397 Thijs
        s->reuse_socket = find_info_tag(buf, sizeof(buf), "reuse", p);
371 2d225591 Fabrice Bellard
        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 9899efb4 Max Krasnyansky
        if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
378
            h->max_packet_size = strtol(buf, NULL, 10);
379
        }
380 236bb1ab Jindřich Makovička
        if (find_info_tag(buf, sizeof(buf), "buffer_size", p)) {
381
            s->buffer_size = strtol(buf, NULL, 10);
382
        }
383 de6d9b64 Fabrice Bellard
    }
384 2d225591 Fabrice Bellard
385
    /* fill the dest addr */
386 6ba5cbc6 Petr Doubek
    url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
387 115329f1 Diego Biurrun
388 2d225591 Fabrice Bellard
    /* XXX: fix url_split */
389
    if (hostname[0] == '\0' || hostname[0] == '?') {
390
        /* only accepts null hostname if input */
391 35b74c3d Luca Abeni
        if (flags & URL_WRONLY)
392 2d225591 Fabrice Bellard
            goto fail;
393
    } else {
394
        udp_set_remote_url(h, uri);
395
    }
396 de6d9b64 Fabrice Bellard
397 882d00f2 Luca Abeni
    if (s->is_multicast && !(h->flags & URL_WRONLY))
398
        s->local_port = port;
399 aa519c47 Luca Abeni
    udp_fd = udp_socket_create(s, &my_addr, &len);
400 2d225591 Fabrice Bellard
    if (udp_fd < 0)
401
        goto fail;
402
403 34ecc397 Thijs
    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 de6d9b64 Fabrice Bellard
    /* the bind is needed to give a port to the socket now */
408 36b53281 Jindřich Makovička
    /* 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 de6d9b64 Fabrice Bellard
        goto fail;
416
417 d4936869 Luca Abeni
    len = sizeof(my_addr);
418
    getsockname(udp_fd, (struct sockaddr *)&my_addr, &len);
419 aa519c47 Luca Abeni
    s->local_port = udp_port(&my_addr, len);
420
421 7a91333f Hans Zandbelt
    if (s->is_multicast) {
422
        if (h->flags & URL_WRONLY) {
423 a8bde059 Luca Abeni
            /* output */
424 9cdcb04f Luca Abeni
            if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0)
425 7a91333f Hans Zandbelt
                goto fail;
426
        } else {
427 a8bde059 Luca Abeni
            /* input */
428 9cdcb04f Luca Abeni
            if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0)
429 7a91333f Hans Zandbelt
                goto fail;
430
        }
431
    }
432 de6d9b64 Fabrice Bellard
433 2d225591 Fabrice Bellard
    if (is_output) {
434
        /* limit the tx buf size to limit latency */
435 236bb1ab Jindřich Makovička
        tmp = s->buffer_size;
436 2d225591 Fabrice Bellard
        if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) {
437 086119b3 Luca Abeni
            av_log(NULL, AV_LOG_ERROR, "setsockopt(SO_SNDBUF): %s\n", strerror(errno));
438 2d225591 Fabrice Bellard
            goto fail;
439
        }
440 f18cae4d Ramiro Polla
    } 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 236bb1ab Jindřich Makovička
        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 ce09d560 Jindřich Makovička
        /* make the socket non-blocking */
448
        ff_socket_nonblock(udp_fd, 1);
449 2d225591 Fabrice Bellard
    }
450
451
    s->udp_fd = udp_fd;
452 de6d9b64 Fabrice Bellard
    return 0;
453
 fail:
454 2d225591 Fabrice Bellard
    if (udp_fd >= 0)
455 9ddd71fc François Revol
        closesocket(udp_fd);
456 2d225591 Fabrice Bellard
    av_free(s);
457 6f3e0b21 Panagiotis Issaris
    return AVERROR(EIO);
458 de6d9b64 Fabrice Bellard
}
459
460 0c1a9eda Zdenek Kabelac
static int udp_read(URLContext *h, uint8_t *buf, int size)
461 de6d9b64 Fabrice Bellard
{
462
    UDPContext *s = h->priv_data;
463 191e8ca7 Måns Rullgård
    int len;
464 7d084299 Jindřich Makovička
    fd_set rfds;
465
    int ret;
466
    struct timeval tv;
467 2d225591 Fabrice Bellard
468
    for(;;) {
469 7d084299 Jindřich Makovička
        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 ce09d560 Jindřich Makovička
        len = recv(s->udp_fd, buf, size, 0);
481 2d225591 Fabrice Bellard
        if (len < 0) {
482 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
483
                ff_neterrno() != FF_NETERROR(EINTR))
484 6f3e0b21 Panagiotis Issaris
                return AVERROR(EIO);
485 2d225591 Fabrice Bellard
        } else {
486
            break;
487
        }
488
    }
489
    return len;
490 de6d9b64 Fabrice Bellard
}
491
492 0c1a9eda Zdenek Kabelac
static int udp_write(URLContext *h, uint8_t *buf, int size)
493 de6d9b64 Fabrice Bellard
{
494
    UDPContext *s = h->priv_data;
495 2d225591 Fabrice Bellard
    int ret;
496
497
    for(;;) {
498 115329f1 Diego Biurrun
        ret = sendto (s->udp_fd, buf, size, 0,
499 2d225591 Fabrice Bellard
                      (struct sockaddr *) &s->dest_addr,
500 7a91333f Hans Zandbelt
                      s->dest_addr_len);
501 2d225591 Fabrice Bellard
        if (ret < 0) {
502 8da4034f Alex Beregszaszi
            if (ff_neterrno() != FF_NETERROR(EINTR) &&
503
                ff_neterrno() != FF_NETERROR(EAGAIN))
504 6f3e0b21 Panagiotis Issaris
                return AVERROR(EIO);
505 2d225591 Fabrice Bellard
        } else {
506
            break;
507
        }
508 de6d9b64 Fabrice Bellard
    }
509 2d225591 Fabrice Bellard
    return size;
510
}
511
512
static int udp_close(URLContext *h)
513
{
514
    UDPContext *s = h->priv_data;
515
516 7a91333f Hans Zandbelt
    if (s->is_multicast && !(h->flags & URL_WRONLY))
517 9cdcb04f Luca Abeni
        udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr);
518 9ddd71fc François Revol
    closesocket(s->udp_fd);
519 1642cb6b Ramiro Polla
    ff_network_close();
520 2d225591 Fabrice Bellard
    av_free(s);
521
    return 0;
522 de6d9b64 Fabrice Bellard
}
523
524
URLProtocol udp_protocol = {
525
    "udp",
526
    udp_open,
527 2d225591 Fabrice Bellard
    udp_read,
528 de6d9b64 Fabrice Bellard
    udp_write,
529
    NULL, /* seek */
530
    udp_close,
531
};