Libav
|
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 "internal.h" 00031 #include "network.h" 00032 #include "os_support.h" 00033 #if HAVE_SYS_SELECT_H 00034 #include <sys/select.h> 00035 #endif 00036 #include <sys/time.h> 00037 00038 #ifndef IPV6_ADD_MEMBERSHIP 00039 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP 00040 #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP 00041 #endif 00042 #ifndef IN_MULTICAST 00043 #define IN_MULTICAST(a) ((((uint32_t)(a)) & 0xf0000000) == 0xe0000000) 00044 #endif 00045 #ifndef IN6_IS_ADDR_MULTICAST 00046 #define IN6_IS_ADDR_MULTICAST(a) (((uint8_t *) (a))[0] == 0xff) 00047 #endif 00048 00049 typedef struct { 00050 int udp_fd; 00051 int ttl; 00052 int buffer_size; 00053 int is_multicast; 00054 int local_port; 00055 int reuse_socket; 00056 struct sockaddr_storage dest_addr; 00057 int dest_addr_len; 00058 } UDPContext; 00059 00060 #define UDP_TX_BUF_SIZE 32768 00061 #define UDP_MAX_PKT_SIZE 65536 00062 00063 static int udp_set_multicast_ttl(int sockfd, int mcastTTL, 00064 struct sockaddr *addr) 00065 { 00066 #ifdef IP_MULTICAST_TTL 00067 if (addr->sa_family == AF_INET) { 00068 if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &mcastTTL, sizeof(mcastTTL)) < 0) { 00069 av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_TTL): %s\n", strerror(errno)); 00070 return -1; 00071 } 00072 } 00073 #endif 00074 #if defined(IPPROTO_IPV6) && defined(IPV6_MULTICAST_HOPS) 00075 if (addr->sa_family == AF_INET6) { 00076 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastTTL, sizeof(mcastTTL)) < 0) { 00077 av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_HOPS): %s\n", strerror(errno)); 00078 return -1; 00079 } 00080 } 00081 #endif 00082 return 0; 00083 } 00084 00085 static int udp_join_multicast_group(int sockfd, struct sockaddr *addr) 00086 { 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 HAVE_STRUCT_IPV6_MREQ 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 { 00116 #ifdef IP_DROP_MEMBERSHIP 00117 if (addr->sa_family == AF_INET) { 00118 struct ip_mreq mreq; 00119 00120 mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; 00121 mreq.imr_interface.s_addr= INADDR_ANY; 00122 if (setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) { 00123 av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_DROP_MEMBERSHIP): %s\n", strerror(errno)); 00124 return -1; 00125 } 00126 } 00127 #endif 00128 #if HAVE_STRUCT_IPV6_MREQ 00129 if (addr->sa_family == AF_INET6) { 00130 struct ipv6_mreq mreq6; 00131 00132 memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr)); 00133 mreq6.ipv6mr_interface= 0; 00134 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) { 00135 av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP): %s\n", strerror(errno)); 00136 return -1; 00137 } 00138 } 00139 #endif 00140 return 0; 00141 } 00142 00143 static struct addrinfo* udp_resolve_host(const char *hostname, int port, 00144 int type, int family, int flags) 00145 { 00146 struct addrinfo hints, *res = 0; 00147 int error; 00148 char sport[16]; 00149 const char *node = 0, *service = "0"; 00150 00151 if (port > 0) { 00152 snprintf(sport, sizeof(sport), "%d", port); 00153 service = sport; 00154 } 00155 if ((hostname) && (hostname[0] != '\0') && (hostname[0] != '?')) { 00156 node = hostname; 00157 } 00158 memset(&hints, 0, sizeof(hints)); 00159 hints.ai_socktype = type; 00160 hints.ai_family = family; 00161 hints.ai_flags = flags; 00162 if ((error = getaddrinfo(node, service, &hints, &res))) { 00163 res = NULL; 00164 av_log(NULL, AV_LOG_ERROR, "udp_resolve_host: %s\n", gai_strerror(error)); 00165 } 00166 00167 return res; 00168 } 00169 00170 static int udp_set_url(struct sockaddr_storage *addr, 00171 const char *hostname, int port) 00172 { 00173 struct addrinfo *res0; 00174 int addr_len; 00175 00176 res0 = udp_resolve_host(hostname, port, SOCK_DGRAM, AF_UNSPEC, 0); 00177 if (res0 == 0) return AVERROR(EIO); 00178 memcpy(addr, res0->ai_addr, res0->ai_addrlen); 00179 addr_len = res0->ai_addrlen; 00180 freeaddrinfo(res0); 00181 00182 return addr_len; 00183 } 00184 00185 static int is_multicast_address(struct sockaddr_storage *addr) 00186 { 00187 if (addr->ss_family == AF_INET) { 00188 return IN_MULTICAST(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr)); 00189 } 00190 #if HAVE_STRUCT_SOCKADDR_IN6 00191 if (addr->ss_family == AF_INET6) { 00192 return IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)addr)->sin6_addr); 00193 } 00194 #endif 00195 00196 return 0; 00197 } 00198 00199 static int udp_socket_create(UDPContext *s, 00200 struct sockaddr_storage *addr, int *addr_len) 00201 { 00202 int udp_fd = -1; 00203 struct addrinfo *res0 = NULL, *res = NULL; 00204 int family = AF_UNSPEC; 00205 00206 if (((struct sockaddr *) &s->dest_addr)->sa_family) 00207 family = ((struct sockaddr *) &s->dest_addr)->sa_family; 00208 res0 = udp_resolve_host(0, s->local_port, SOCK_DGRAM, family, AI_PASSIVE); 00209 if (res0 == 0) 00210 goto fail; 00211 for (res = res0; res; res=res->ai_next) { 00212 udp_fd = socket(res->ai_family, SOCK_DGRAM, 0); 00213 if (udp_fd > 0) break; 00214 av_log(NULL, AV_LOG_ERROR, "socket: %s\n", strerror(errno)); 00215 } 00216 00217 if (udp_fd < 0) 00218 goto fail; 00219 00220 memcpy(addr, res->ai_addr, res->ai_addrlen); 00221 *addr_len = res->ai_addrlen; 00222 00223 freeaddrinfo(res0); 00224 00225 return udp_fd; 00226 00227 fail: 00228 if (udp_fd >= 0) 00229 closesocket(udp_fd); 00230 if(res0) 00231 freeaddrinfo(res0); 00232 return -1; 00233 } 00234 00235 static int udp_port(struct sockaddr_storage *addr, int addr_len) 00236 { 00237 char sbuf[sizeof(int)*3+1]; 00238 00239 if (getnameinfo((struct sockaddr *)addr, addr_len, NULL, 0, sbuf, sizeof(sbuf), NI_NUMERICSERV) != 0) { 00240 av_log(NULL, AV_LOG_ERROR, "getnameinfo: %s\n", strerror(errno)); 00241 return -1; 00242 } 00243 00244 return strtol(sbuf, NULL, 10); 00245 } 00246 00247 00263 int udp_set_remote_url(URLContext *h, const char *uri) 00264 { 00265 UDPContext *s = h->priv_data; 00266 char hostname[256]; 00267 int port; 00268 00269 ff_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); 00270 00271 /* set the destination address */ 00272 s->dest_addr_len = udp_set_url(&s->dest_addr, hostname, port); 00273 if (s->dest_addr_len < 0) { 00274 return AVERROR(EIO); 00275 } 00276 s->is_multicast = is_multicast_address(&s->dest_addr); 00277 00278 return 0; 00279 } 00280 00286 int udp_get_local_port(URLContext *h) 00287 { 00288 UDPContext *s = h->priv_data; 00289 return s->local_port; 00290 } 00291 00297 #if (LIBAVFORMAT_VERSION_MAJOR >= 53) 00298 static 00299 #endif 00300 int udp_get_file_handle(URLContext *h) 00301 { 00302 UDPContext *s = h->priv_data; 00303 return s->udp_fd; 00304 } 00305 00306 /* put it in UDP context */ 00307 /* return non zero if error */ 00308 static int udp_open(URLContext *h, const char *uri, int flags) 00309 { 00310 char hostname[1024]; 00311 int port, udp_fd = -1, tmp, bind_ret = -1; 00312 UDPContext *s = NULL; 00313 int is_output; 00314 const char *p; 00315 char buf[256]; 00316 struct sockaddr_storage my_addr; 00317 int len; 00318 00319 h->is_streamed = 1; 00320 h->max_packet_size = 1472; 00321 00322 is_output = (flags & URL_WRONLY); 00323 00324 s = av_mallocz(sizeof(UDPContext)); 00325 if (!s) 00326 return AVERROR(ENOMEM); 00327 00328 h->priv_data = s; 00329 s->ttl = 16; 00330 s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE; 00331 00332 p = strchr(uri, '?'); 00333 if (p) { 00334 s->reuse_socket = find_info_tag(buf, sizeof(buf), "reuse", p); 00335 if (find_info_tag(buf, sizeof(buf), "ttl", p)) { 00336 s->ttl = strtol(buf, NULL, 10); 00337 } 00338 if (find_info_tag(buf, sizeof(buf), "localport", p)) { 00339 s->local_port = strtol(buf, NULL, 10); 00340 } 00341 if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) { 00342 h->max_packet_size = strtol(buf, NULL, 10); 00343 } 00344 if (find_info_tag(buf, sizeof(buf), "buffer_size", p)) { 00345 s->buffer_size = strtol(buf, NULL, 10); 00346 } 00347 } 00348 00349 /* fill the dest addr */ 00350 ff_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); 00351 00352 /* XXX: fix ff_url_split */ 00353 if (hostname[0] == '\0' || hostname[0] == '?') { 00354 /* only accepts null hostname if input */ 00355 if (flags & URL_WRONLY) 00356 goto fail; 00357 } else { 00358 udp_set_remote_url(h, uri); 00359 } 00360 00361 if (s->is_multicast && !(h->flags & URL_WRONLY)) 00362 s->local_port = port; 00363 udp_fd = udp_socket_create(s, &my_addr, &len); 00364 if (udp_fd < 0) 00365 goto fail; 00366 00367 if (s->reuse_socket) 00368 if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0) 00369 goto fail; 00370 00371 /* the bind is needed to give a port to the socket now */ 00372 /* if multicast, try the multicast address bind first */ 00373 if (s->is_multicast && !(h->flags & URL_WRONLY)) { 00374 bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len); 00375 } 00376 /* bind to the local address if not multicast or if the multicast 00377 * bind failed */ 00378 if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) 00379 goto fail; 00380 00381 len = sizeof(my_addr); 00382 getsockname(udp_fd, (struct sockaddr *)&my_addr, &len); 00383 s->local_port = udp_port(&my_addr, len); 00384 00385 if (s->is_multicast) { 00386 if (h->flags & URL_WRONLY) { 00387 /* output */ 00388 if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0) 00389 goto fail; 00390 } else { 00391 /* input */ 00392 if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0) 00393 goto fail; 00394 } 00395 } 00396 00397 if (is_output) { 00398 /* limit the tx buf size to limit latency */ 00399 tmp = s->buffer_size; 00400 if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) { 00401 av_log(NULL, AV_LOG_ERROR, "setsockopt(SO_SNDBUF): %s\n", strerror(errno)); 00402 goto fail; 00403 } 00404 } else { 00405 /* set udp recv buffer size to the largest possible udp packet size to 00406 * avoid losing data on OSes that set this too low by default. */ 00407 tmp = s->buffer_size; 00408 if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) { 00409 av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_RECVBUF): %s\n", strerror(errno)); 00410 } 00411 /* make the socket non-blocking */ 00412 ff_socket_nonblock(udp_fd, 1); 00413 } 00414 00415 s->udp_fd = udp_fd; 00416 return 0; 00417 fail: 00418 if (udp_fd >= 0) 00419 closesocket(udp_fd); 00420 av_free(s); 00421 return AVERROR(EIO); 00422 } 00423 00424 static int udp_read(URLContext *h, uint8_t *buf, int size) 00425 { 00426 UDPContext *s = h->priv_data; 00427 int len; 00428 fd_set rfds; 00429 int ret; 00430 struct timeval tv; 00431 00432 for(;;) { 00433 if (url_interrupt_cb()) 00434 return AVERROR(EINTR); 00435 FD_ZERO(&rfds); 00436 FD_SET(s->udp_fd, &rfds); 00437 tv.tv_sec = 0; 00438 tv.tv_usec = 100 * 1000; 00439 ret = select(s->udp_fd + 1, &rfds, NULL, NULL, &tv); 00440 if (ret < 0) { 00441 if (ff_neterrno() == FF_NETERROR(EINTR)) 00442 continue; 00443 return AVERROR(EIO); 00444 } 00445 if (!(ret > 0 && FD_ISSET(s->udp_fd, &rfds))) 00446 continue; 00447 len = recv(s->udp_fd, buf, size, 0); 00448 if (len < 0) { 00449 if (ff_neterrno() != FF_NETERROR(EAGAIN) && 00450 ff_neterrno() != FF_NETERROR(EINTR)) 00451 return AVERROR(EIO); 00452 } else { 00453 break; 00454 } 00455 } 00456 return len; 00457 } 00458 00459 static int udp_write(URLContext *h, uint8_t *buf, int size) 00460 { 00461 UDPContext *s = h->priv_data; 00462 int ret; 00463 00464 for(;;) { 00465 ret = sendto (s->udp_fd, buf, size, 0, 00466 (struct sockaddr *) &s->dest_addr, 00467 s->dest_addr_len); 00468 if (ret < 0) { 00469 if (ff_neterrno() != FF_NETERROR(EINTR) && 00470 ff_neterrno() != FF_NETERROR(EAGAIN)) 00471 return AVERROR(EIO); 00472 } else { 00473 break; 00474 } 00475 } 00476 return size; 00477 } 00478 00479 static int udp_close(URLContext *h) 00480 { 00481 UDPContext *s = h->priv_data; 00482 00483 if (s->is_multicast && !(h->flags & URL_WRONLY)) 00484 udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr); 00485 closesocket(s->udp_fd); 00486 av_free(s); 00487 return 0; 00488 } 00489 00490 URLProtocol udp_protocol = { 00491 "udp", 00492 udp_open, 00493 udp_read, 00494 udp_write, 00495 NULL, /* seek */ 00496 udp_close, 00497 .url_get_file_handle = udp_get_file_handle, 00498 };