• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavformat/udp.c

Go to the documentation of this file.
00001 /*
00002  * UDP prototype streaming system
00003  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00027 #define _BSD_SOURCE     /* Needed for using struct ip_mreq with recent glibc */
00028 #include "avformat.h"
00029 #include <unistd.h>
00030 #include "network.h"
00031 #include "os_support.h"
00032 #if HAVE_SYS_SELECT_H
00033 #include <sys/select.h>
00034 #endif
00035 #include <sys/time.h>
00036 
00037 #ifndef IPV6_ADD_MEMBERSHIP
00038 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
00039 #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
00040 #endif
00041 #ifndef IN_MULTICAST
00042 #define IN_MULTICAST(a) ((((uint32_t)(a)) & 0xf0000000) == 0xe0000000)
00043 #endif
00044 #ifndef IN6_IS_ADDR_MULTICAST
00045 #define IN6_IS_ADDR_MULTICAST(a) (((uint8_t *) (a))[0] == 0xff)
00046 #endif
00047 
00048 typedef struct {
00049     int udp_fd;
00050     int ttl;
00051     int buffer_size;
00052     int is_multicast;
00053     int local_port;
00054     int reuse_socket;
00055 #if !CONFIG_IPV6
00056     struct sockaddr_in dest_addr;
00057 #else
00058     struct sockaddr_storage dest_addr;
00059 #endif
00060     int dest_addr_len;
00061 } UDPContext;
00062 
00063 #define UDP_TX_BUF_SIZE 32768
00064 #define UDP_MAX_PKT_SIZE 65536
00065 
00066 static int udp_set_multicast_ttl(int sockfd, int mcastTTL, struct sockaddr *addr) {
00067 #ifdef IP_MULTICAST_TTL
00068     if (addr->sa_family == AF_INET) {
00069         if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &mcastTTL, sizeof(mcastTTL)) < 0) {
00070             av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_TTL): %s\n", strerror(errno));
00071             return -1;
00072         }
00073     }
00074 #endif
00075 #if CONFIG_IPV6
00076     if (addr->sa_family == AF_INET6) {
00077         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastTTL, sizeof(mcastTTL)) < 0) {
00078             av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_HOPS): %s\n", strerror(errno));
00079             return -1;
00080         }
00081     }
00082 #endif
00083     return 0;
00084 }
00085 
00086 static int udp_join_multicast_group(int sockfd, struct sockaddr *addr) {
00087 #ifdef IP_ADD_MEMBERSHIP
00088     if (addr->sa_family == AF_INET) {
00089         struct ip_mreq mreq;
00090 
00091         mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
00092         mreq.imr_interface.s_addr= INADDR_ANY;
00093         if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
00094             av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno));
00095             return -1;
00096         }
00097     }
00098 #endif
00099 #if CONFIG_IPV6
00100     if (addr->sa_family == AF_INET6) {
00101         struct ipv6_mreq mreq6;
00102 
00103         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
00104         mreq6.ipv6mr_interface= 0;
00105         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
00106             av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP): %s\n", strerror(errno));
00107             return -1;
00108         }
00109     }
00110 #endif
00111     return 0;
00112 }
00113 
00114 static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr) {
00115 #ifdef IP_DROP_MEMBERSHIP
00116     if (addr->sa_family == AF_INET) {
00117         struct ip_mreq mreq;
00118 
00119         mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
00120         mreq.imr_interface.s_addr= INADDR_ANY;
00121         if (setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
00122             av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_DROP_MEMBERSHIP): %s\n", strerror(errno));
00123             return -1;
00124         }
00125     }
00126 #endif
00127 #if CONFIG_IPV6
00128     if (addr->sa_family == AF_INET6) {
00129         struct ipv6_mreq mreq6;
00130 
00131         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
00132         mreq6.ipv6mr_interface= 0;
00133         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
00134             av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP): %s\n", strerror(errno));
00135             return -1;
00136         }
00137     }
00138 #endif
00139     return 0;
00140 }
00141 
00142 #if CONFIG_IPV6
00143 static struct addrinfo* udp_ipv6_resolve_host(const char *hostname, int port, int type, int family, int flags) {
00144     struct addrinfo hints, *res = 0;
00145     int error;
00146     char sport[16];
00147     const char *node = 0, *service = "0";
00148 
00149     if (port > 0) {
00150         snprintf(sport, sizeof(sport), "%d", port);
00151         service = sport;
00152     }
00153     if ((hostname) && (hostname[0] != '\0') && (hostname[0] != '?')) {
00154         node = hostname;
00155     }
00156     memset(&hints, 0, sizeof(hints));
00157     hints.ai_socktype = type;
00158     hints.ai_family   = family;
00159     hints.ai_flags = flags;
00160     if ((error = getaddrinfo(node, service, &hints, &res))) {
00161         av_log(NULL, AV_LOG_ERROR, "udp_ipv6_resolve_host: %s\n", gai_strerror(error));
00162     }
00163 
00164     return res;
00165 }
00166 
00167 static int udp_set_url(struct sockaddr_storage *addr, const char *hostname, int port) {
00168     struct addrinfo *res0;
00169     int addr_len;
00170 
00171     res0 = udp_ipv6_resolve_host(hostname, port, SOCK_DGRAM, AF_UNSPEC, 0);
00172     if (res0 == 0) return AVERROR(EIO);
00173     memcpy(addr, res0->ai_addr, res0->ai_addrlen);
00174     addr_len = res0->ai_addrlen;
00175     freeaddrinfo(res0);
00176 
00177     return addr_len;
00178 }
00179 
00180 static int is_multicast_address(struct sockaddr_storage *addr)
00181 {
00182     if (addr->ss_family == AF_INET) {
00183         return IN_MULTICAST(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr));
00184     }
00185     if (addr->ss_family == AF_INET6) {
00186         return IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)addr)->sin6_addr);
00187     }
00188 
00189     return 0;
00190 }
00191 
00192 static int udp_socket_create(UDPContext *s, struct sockaddr_storage *addr, int *addr_len)
00193 {
00194     int udp_fd = -1;
00195     struct addrinfo *res0 = NULL, *res = NULL;
00196     int family = AF_UNSPEC;
00197 
00198     if (((struct sockaddr *) &s->dest_addr)->sa_family)
00199         family = ((struct sockaddr *) &s->dest_addr)->sa_family;
00200     res0 = udp_ipv6_resolve_host(0, s->local_port, SOCK_DGRAM, family, AI_PASSIVE);
00201     if (res0 == 0)
00202         goto fail;
00203     for (res = res0; res; res=res->ai_next) {
00204         udp_fd = socket(res->ai_family, SOCK_DGRAM, 0);
00205         if (udp_fd > 0) break;
00206         av_log(NULL, AV_LOG_ERROR, "socket: %s\n", strerror(errno));
00207     }
00208 
00209     if (udp_fd < 0)
00210         goto fail;
00211 
00212     memcpy(addr, res->ai_addr, res->ai_addrlen);
00213     *addr_len = res->ai_addrlen;
00214 
00215     freeaddrinfo(res0);
00216 
00217     return udp_fd;
00218 
00219  fail:
00220     if (udp_fd >= 0)
00221         closesocket(udp_fd);
00222     if(res0)
00223         freeaddrinfo(res0);
00224     return -1;
00225 }
00226 
00227 static int udp_port(struct sockaddr_storage *addr, int addr_len)
00228 {
00229     char sbuf[sizeof(int)*3+1];
00230 
00231     if (getnameinfo((struct sockaddr *)addr, addr_len, NULL, 0,  sbuf, sizeof(sbuf), NI_NUMERICSERV) != 0) {
00232         av_log(NULL, AV_LOG_ERROR, "getnameinfo: %s\n", strerror(errno));
00233         return -1;
00234     }
00235 
00236     return strtol(sbuf, NULL, 10);
00237 }
00238 
00239 #else
00240 
00241 static int udp_set_url(struct sockaddr_in *addr, const char *hostname, int port)
00242 {
00243     /* set the destination address */
00244     if (resolve_host(&addr->sin_addr, hostname) < 0)
00245         return AVERROR(EIO);
00246     addr->sin_family = AF_INET;
00247     addr->sin_port = htons(port);
00248 
00249     return sizeof(struct sockaddr_in);
00250 }
00251 
00252 static int is_multicast_address(struct sockaddr_in *addr)
00253 {
00254     return IN_MULTICAST(ntohl(addr->sin_addr.s_addr));
00255 }
00256 
00257 static int udp_socket_create(UDPContext *s, struct sockaddr_in *addr, int *addr_len)
00258 {
00259     int fd;
00260 
00261     fd = socket(AF_INET, SOCK_DGRAM, 0);
00262     if (fd < 0)
00263         return -1;
00264 
00265     addr->sin_family = AF_INET;
00266     addr->sin_addr.s_addr = htonl (INADDR_ANY);
00267     addr->sin_port = htons(s->local_port);
00268     *addr_len = sizeof(struct sockaddr_in);
00269 
00270     return fd;
00271 }
00272 
00273 static int udp_port(struct sockaddr_in *addr, int len)
00274 {
00275     return ntohs(addr->sin_port);
00276 }
00277 #endif /* CONFIG_IPV6 */
00278 
00279 
00295 int udp_set_remote_url(URLContext *h, const char *uri)
00296 {
00297     UDPContext *s = h->priv_data;
00298     char hostname[256];
00299     int port;
00300 
00301     url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
00302 
00303     /* set the destination address */
00304     s->dest_addr_len = udp_set_url(&s->dest_addr, hostname, port);
00305     if (s->dest_addr_len < 0) {
00306         return AVERROR(EIO);
00307     }
00308     s->is_multicast = is_multicast_address(&s->dest_addr);
00309 
00310     return 0;
00311 }
00312 
00318 int udp_get_local_port(URLContext *h)
00319 {
00320     UDPContext *s = h->priv_data;
00321     return s->local_port;
00322 }
00323 
00329 int udp_get_file_handle(URLContext *h)
00330 {
00331     UDPContext *s = h->priv_data;
00332     return s->udp_fd;
00333 }
00334 
00335 /* put it in UDP context */
00336 /* return non zero if error */
00337 static int udp_open(URLContext *h, const char *uri, int flags)
00338 {
00339     char hostname[1024];
00340     int port, udp_fd = -1, tmp, bind_ret = -1;
00341     UDPContext *s = NULL;
00342     int is_output;
00343     const char *p;
00344     char buf[256];
00345 #if !CONFIG_IPV6
00346     struct sockaddr_in my_addr;
00347 #else
00348     struct sockaddr_storage my_addr;
00349 #endif
00350     int len;
00351 
00352     h->is_streamed = 1;
00353     h->max_packet_size = 1472;
00354 
00355     is_output = (flags & URL_WRONLY);
00356 
00357     if(!ff_network_init())
00358         return AVERROR(EIO);
00359 
00360     s = av_mallocz(sizeof(UDPContext));
00361     if (!s)
00362         return AVERROR(ENOMEM);
00363 
00364     h->priv_data = s;
00365     s->ttl = 16;
00366     s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE;
00367 
00368     p = strchr(uri, '?');
00369     if (p) {
00370         s->reuse_socket = find_info_tag(buf, sizeof(buf), "reuse", p);
00371         if (find_info_tag(buf, sizeof(buf), "ttl", p)) {
00372             s->ttl = strtol(buf, NULL, 10);
00373         }
00374         if (find_info_tag(buf, sizeof(buf), "localport", p)) {
00375             s->local_port = strtol(buf, NULL, 10);
00376         }
00377         if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
00378             h->max_packet_size = strtol(buf, NULL, 10);
00379         }
00380         if (find_info_tag(buf, sizeof(buf), "buffer_size", p)) {
00381             s->buffer_size = strtol(buf, NULL, 10);
00382         }
00383     }
00384 
00385     /* fill the dest addr */
00386     url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
00387 
00388     /* XXX: fix url_split */
00389     if (hostname[0] == '\0' || hostname[0] == '?') {
00390         /* only accepts null hostname if input */
00391         if (flags & URL_WRONLY)
00392             goto fail;
00393     } else {
00394         udp_set_remote_url(h, uri);
00395     }
00396 
00397     if (s->is_multicast && !(h->flags & URL_WRONLY))
00398         s->local_port = port;
00399     udp_fd = udp_socket_create(s, &my_addr, &len);
00400     if (udp_fd < 0)
00401         goto fail;
00402 
00403     if (s->reuse_socket)
00404         if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0)
00405             goto fail;
00406 
00407     /* the bind is needed to give a port to the socket now */
00408     /* if multicast, try the multicast address bind first */
00409     if (s->is_multicast && !(h->flags & URL_WRONLY)) {
00410         bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len);
00411     }
00412     /* bind to the local address if not multicast or if the multicast
00413      * bind failed */
00414     if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0)
00415         goto fail;
00416 
00417     len = sizeof(my_addr);
00418     getsockname(udp_fd, (struct sockaddr *)&my_addr, &len);
00419     s->local_port = udp_port(&my_addr, len);
00420 
00421     if (s->is_multicast) {
00422         if (h->flags & URL_WRONLY) {
00423             /* output */
00424             if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0)
00425                 goto fail;
00426         } else {
00427             /* input */
00428             if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0)
00429                 goto fail;
00430         }
00431     }
00432 
00433     if (is_output) {
00434         /* limit the tx buf size to limit latency */
00435         tmp = s->buffer_size;
00436         if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) {
00437             av_log(NULL, AV_LOG_ERROR, "setsockopt(SO_SNDBUF): %s\n", strerror(errno));
00438             goto fail;
00439         }
00440     } else {
00441         /* set udp recv buffer size to the largest possible udp packet size to
00442          * avoid losing data on OSes that set this too low by default. */
00443         tmp = s->buffer_size;
00444         if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) {
00445             av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_RECVBUF): %s\n", strerror(errno));
00446         }
00447         /* make the socket non-blocking */
00448         ff_socket_nonblock(udp_fd, 1);
00449     }
00450 
00451     s->udp_fd = udp_fd;
00452     return 0;
00453  fail:
00454     if (udp_fd >= 0)
00455         closesocket(udp_fd);
00456     av_free(s);
00457     return AVERROR(EIO);
00458 }
00459 
00460 static int udp_read(URLContext *h, uint8_t *buf, int size)
00461 {
00462     UDPContext *s = h->priv_data;
00463     int len;
00464     fd_set rfds;
00465     int ret;
00466     struct timeval tv;
00467 
00468     for(;;) {
00469         if (url_interrupt_cb())
00470             return AVERROR(EINTR);
00471         FD_ZERO(&rfds);
00472         FD_SET(s->udp_fd, &rfds);
00473         tv.tv_sec = 0;
00474         tv.tv_usec = 100 * 1000;
00475         ret = select(s->udp_fd + 1, &rfds, NULL, NULL, &tv);
00476         if (ret < 0)
00477             return AVERROR(EIO);
00478         if (!(ret > 0 && FD_ISSET(s->udp_fd, &rfds)))
00479             continue;
00480         len = recv(s->udp_fd, buf, size, 0);
00481         if (len < 0) {
00482             if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
00483                 ff_neterrno() != FF_NETERROR(EINTR))
00484                 return AVERROR(EIO);
00485         } else {
00486             break;
00487         }
00488     }
00489     return len;
00490 }
00491 
00492 static int udp_write(URLContext *h, uint8_t *buf, int size)
00493 {
00494     UDPContext *s = h->priv_data;
00495     int ret;
00496 
00497     for(;;) {
00498         ret = sendto (s->udp_fd, buf, size, 0,
00499                       (struct sockaddr *) &s->dest_addr,
00500                       s->dest_addr_len);
00501         if (ret < 0) {
00502             if (ff_neterrno() != FF_NETERROR(EINTR) &&
00503                 ff_neterrno() != FF_NETERROR(EAGAIN))
00504                 return AVERROR(EIO);
00505         } else {
00506             break;
00507         }
00508     }
00509     return size;
00510 }
00511 
00512 static int udp_close(URLContext *h)
00513 {
00514     UDPContext *s = h->priv_data;
00515 
00516     if (s->is_multicast && !(h->flags & URL_WRONLY))
00517         udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr);
00518     closesocket(s->udp_fd);
00519     ff_network_close();
00520     av_free(s);
00521     return 0;
00522 }
00523 
00524 URLProtocol udp_protocol = {
00525     "udp",
00526     udp_open,
00527     udp_read,
00528     udp_write,
00529     NULL, /* seek */
00530     udp_close,
00531 };

Generated on Tue Nov 4 2014 12:59:24 for ffmpeg by  doxygen 1.7.1