Libav 0.7.1
|
00001 /* 00002 * UDP prototype streaming system 00003 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav 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 * Libav 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 Libav; 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 00029 #include "avformat.h" 00030 #include "avio_internal.h" 00031 #include "libavutil/parseutils.h" 00032 #include <unistd.h> 00033 #include "internal.h" 00034 #include "network.h" 00035 #include "os_support.h" 00036 #include "url.h" 00037 #include <sys/time.h> 00038 00039 #ifndef IPV6_ADD_MEMBERSHIP 00040 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP 00041 #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP 00042 #endif 00043 00044 typedef struct { 00045 int udp_fd; 00046 int ttl; 00047 int buffer_size; 00048 int is_multicast; 00049 int local_port; 00050 int reuse_socket; 00051 struct sockaddr_storage dest_addr; 00052 int dest_addr_len; 00053 int is_connected; 00054 } UDPContext; 00055 00056 #define UDP_TX_BUF_SIZE 32768 00057 #define UDP_MAX_PKT_SIZE 65536 00058 00059 static int udp_set_multicast_ttl(int sockfd, int mcastTTL, 00060 struct sockaddr *addr) 00061 { 00062 #ifdef IP_MULTICAST_TTL 00063 if (addr->sa_family == AF_INET) { 00064 if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &mcastTTL, sizeof(mcastTTL)) < 0) { 00065 av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_TTL): %s\n", strerror(errno)); 00066 return -1; 00067 } 00068 } 00069 #endif 00070 #if defined(IPPROTO_IPV6) && defined(IPV6_MULTICAST_HOPS) 00071 if (addr->sa_family == AF_INET6) { 00072 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastTTL, sizeof(mcastTTL)) < 0) { 00073 av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_HOPS): %s\n", strerror(errno)); 00074 return -1; 00075 } 00076 } 00077 #endif 00078 return 0; 00079 } 00080 00081 static int udp_join_multicast_group(int sockfd, struct sockaddr *addr) 00082 { 00083 #ifdef IP_ADD_MEMBERSHIP 00084 if (addr->sa_family == AF_INET) { 00085 struct ip_mreq mreq; 00086 00087 mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; 00088 mreq.imr_interface.s_addr= INADDR_ANY; 00089 if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) { 00090 av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno)); 00091 return -1; 00092 } 00093 } 00094 #endif 00095 #if HAVE_STRUCT_IPV6_MREQ && defined(IPPROTO_IPV6) 00096 if (addr->sa_family == AF_INET6) { 00097 struct ipv6_mreq mreq6; 00098 00099 memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr)); 00100 mreq6.ipv6mr_interface= 0; 00101 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) { 00102 av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP): %s\n", strerror(errno)); 00103 return -1; 00104 } 00105 } 00106 #endif 00107 return 0; 00108 } 00109 00110 static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr) 00111 { 00112 #ifdef IP_DROP_MEMBERSHIP 00113 if (addr->sa_family == AF_INET) { 00114 struct ip_mreq mreq; 00115 00116 mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; 00117 mreq.imr_interface.s_addr= INADDR_ANY; 00118 if (setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) { 00119 av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_DROP_MEMBERSHIP): %s\n", strerror(errno)); 00120 return -1; 00121 } 00122 } 00123 #endif 00124 #if HAVE_STRUCT_IPV6_MREQ && defined(IPPROTO_IPV6) 00125 if (addr->sa_family == AF_INET6) { 00126 struct ipv6_mreq mreq6; 00127 00128 memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr)); 00129 mreq6.ipv6mr_interface= 0; 00130 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) { 00131 av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP): %s\n", strerror(errno)); 00132 return -1; 00133 } 00134 } 00135 #endif 00136 return 0; 00137 } 00138 00139 static struct addrinfo* udp_resolve_host(const char *hostname, int port, 00140 int type, int family, int flags) 00141 { 00142 struct addrinfo hints, *res = 0; 00143 int error; 00144 char sport[16]; 00145 const char *node = 0, *service = "0"; 00146 00147 if (port > 0) { 00148 snprintf(sport, sizeof(sport), "%d", port); 00149 service = sport; 00150 } 00151 if ((hostname) && (hostname[0] != '\0') && (hostname[0] != '?')) { 00152 node = hostname; 00153 } 00154 memset(&hints, 0, sizeof(hints)); 00155 hints.ai_socktype = type; 00156 hints.ai_family = family; 00157 hints.ai_flags = flags; 00158 if ((error = getaddrinfo(node, service, &hints, &res))) { 00159 res = NULL; 00160 av_log(NULL, AV_LOG_ERROR, "udp_resolve_host: %s\n", gai_strerror(error)); 00161 } 00162 00163 return res; 00164 } 00165 00166 static int udp_set_url(struct sockaddr_storage *addr, 00167 const char *hostname, int port) 00168 { 00169 struct addrinfo *res0; 00170 int addr_len; 00171 00172 res0 = udp_resolve_host(hostname, port, SOCK_DGRAM, AF_UNSPEC, 0); 00173 if (res0 == 0) return AVERROR(EIO); 00174 memcpy(addr, res0->ai_addr, res0->ai_addrlen); 00175 addr_len = res0->ai_addrlen; 00176 freeaddrinfo(res0); 00177 00178 return addr_len; 00179 } 00180 00181 static int udp_socket_create(UDPContext *s, 00182 struct sockaddr_storage *addr, int *addr_len) 00183 { 00184 int udp_fd = -1; 00185 struct addrinfo *res0 = NULL, *res = NULL; 00186 int family = AF_UNSPEC; 00187 00188 if (((struct sockaddr *) &s->dest_addr)->sa_family) 00189 family = ((struct sockaddr *) &s->dest_addr)->sa_family; 00190 res0 = udp_resolve_host(0, s->local_port, SOCK_DGRAM, family, AI_PASSIVE); 00191 if (res0 == 0) 00192 goto fail; 00193 for (res = res0; res; res=res->ai_next) { 00194 udp_fd = socket(res->ai_family, SOCK_DGRAM, 0); 00195 if (udp_fd > 0) break; 00196 av_log(NULL, AV_LOG_ERROR, "socket: %s\n", strerror(errno)); 00197 } 00198 00199 if (udp_fd < 0) 00200 goto fail; 00201 00202 memcpy(addr, res->ai_addr, res->ai_addrlen); 00203 *addr_len = res->ai_addrlen; 00204 00205 freeaddrinfo(res0); 00206 00207 return udp_fd; 00208 00209 fail: 00210 if (udp_fd >= 0) 00211 closesocket(udp_fd); 00212 if(res0) 00213 freeaddrinfo(res0); 00214 return -1; 00215 } 00216 00217 static int udp_port(struct sockaddr_storage *addr, int addr_len) 00218 { 00219 char sbuf[sizeof(int)*3+1]; 00220 00221 if (getnameinfo((struct sockaddr *)addr, addr_len, NULL, 0, sbuf, sizeof(sbuf), NI_NUMERICSERV) != 0) { 00222 av_log(NULL, AV_LOG_ERROR, "getnameinfo: %s\n", strerror(errno)); 00223 return -1; 00224 } 00225 00226 return strtol(sbuf, NULL, 10); 00227 } 00228 00229 00245 int ff_udp_set_remote_url(URLContext *h, const char *uri) 00246 { 00247 UDPContext *s = h->priv_data; 00248 char hostname[256], buf[10]; 00249 int port; 00250 const char *p; 00251 00252 av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); 00253 00254 /* set the destination address */ 00255 s->dest_addr_len = udp_set_url(&s->dest_addr, hostname, port); 00256 if (s->dest_addr_len < 0) { 00257 return AVERROR(EIO); 00258 } 00259 s->is_multicast = ff_is_multicast_address((struct sockaddr*) &s->dest_addr); 00260 p = strchr(uri, '?'); 00261 if (p) { 00262 if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { 00263 int was_connected = s->is_connected; 00264 s->is_connected = strtol(buf, NULL, 10); 00265 if (s->is_connected && !was_connected) { 00266 if (connect(s->udp_fd, (struct sockaddr *) &s->dest_addr, 00267 s->dest_addr_len)) { 00268 s->is_connected = 0; 00269 av_log(h, AV_LOG_ERROR, "connect: %s\n", strerror(errno)); 00270 return AVERROR(EIO); 00271 } 00272 } 00273 } 00274 } 00275 00276 return 0; 00277 } 00278 00284 int ff_udp_get_local_port(URLContext *h) 00285 { 00286 UDPContext *s = h->priv_data; 00287 return s->local_port; 00288 } 00289 00295 static int udp_get_file_handle(URLContext *h) 00296 { 00297 UDPContext *s = h->priv_data; 00298 return s->udp_fd; 00299 } 00300 00301 /* put it in UDP context */ 00302 /* return non zero if error */ 00303 static int udp_open(URLContext *h, const char *uri, int flags) 00304 { 00305 char hostname[1024]; 00306 int port, udp_fd = -1, tmp, bind_ret = -1; 00307 UDPContext *s = NULL; 00308 int is_output; 00309 const char *p; 00310 char buf[256]; 00311 struct sockaddr_storage my_addr; 00312 int len; 00313 int reuse_specified = 0; 00314 00315 h->is_streamed = 1; 00316 h->max_packet_size = 1472; 00317 00318 is_output = !(flags & AVIO_FLAG_READ); 00319 00320 s = av_mallocz(sizeof(UDPContext)); 00321 if (!s) 00322 return AVERROR(ENOMEM); 00323 00324 h->priv_data = s; 00325 s->ttl = 16; 00326 s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE; 00327 00328 p = strchr(uri, '?'); 00329 if (p) { 00330 if (av_find_info_tag(buf, sizeof(buf), "reuse", p)) { 00331 const char *endptr=NULL; 00332 s->reuse_socket = strtol(buf, &endptr, 10); 00333 /* assume if no digits were found it is a request to enable it */ 00334 if (buf == endptr) 00335 s->reuse_socket = 1; 00336 reuse_specified = 1; 00337 } 00338 if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) { 00339 s->ttl = strtol(buf, NULL, 10); 00340 } 00341 if (av_find_info_tag(buf, sizeof(buf), "localport", p)) { 00342 s->local_port = strtol(buf, NULL, 10); 00343 } 00344 if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) { 00345 h->max_packet_size = strtol(buf, NULL, 10); 00346 } 00347 if (av_find_info_tag(buf, sizeof(buf), "buffer_size", p)) { 00348 s->buffer_size = strtol(buf, NULL, 10); 00349 } 00350 if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { 00351 s->is_connected = strtol(buf, NULL, 10); 00352 } 00353 } 00354 00355 /* fill the dest addr */ 00356 av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); 00357 00358 /* XXX: fix av_url_split */ 00359 if (hostname[0] == '\0' || hostname[0] == '?') { 00360 /* only accepts null hostname if input */ 00361 if (!(flags & AVIO_FLAG_READ)) 00362 goto fail; 00363 } else { 00364 if (ff_udp_set_remote_url(h, uri) < 0) 00365 goto fail; 00366 } 00367 00368 if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) 00369 s->local_port = port; 00370 udp_fd = udp_socket_create(s, &my_addr, &len); 00371 if (udp_fd < 0) 00372 goto fail; 00373 00374 /* Follow the requested reuse option, unless it's multicast in which 00375 * case enable reuse unless explicitely disabled. 00376 */ 00377 if (s->reuse_socket || (s->is_multicast && !reuse_specified)) { 00378 s->reuse_socket = 1; 00379 if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0) 00380 goto fail; 00381 } 00382 00383 /* the bind is needed to give a port to the socket now */ 00384 /* if multicast, try the multicast address bind first */ 00385 if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) { 00386 bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len); 00387 } 00388 /* bind to the local address if not multicast or if the multicast 00389 * bind failed */ 00390 if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) 00391 goto fail; 00392 00393 len = sizeof(my_addr); 00394 getsockname(udp_fd, (struct sockaddr *)&my_addr, &len); 00395 s->local_port = udp_port(&my_addr, len); 00396 00397 if (s->is_multicast) { 00398 if (!(h->flags & AVIO_FLAG_READ)) { 00399 /* output */ 00400 if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0) 00401 goto fail; 00402 } else { 00403 /* input */ 00404 if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0) 00405 goto fail; 00406 } 00407 } 00408 00409 if (is_output) { 00410 /* limit the tx buf size to limit latency */ 00411 tmp = s->buffer_size; 00412 if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) { 00413 av_log(h, AV_LOG_ERROR, "setsockopt(SO_SNDBUF): %s\n", strerror(errno)); 00414 goto fail; 00415 } 00416 } else { 00417 /* set udp recv buffer size to the largest possible udp packet size to 00418 * avoid losing data on OSes that set this too low by default. */ 00419 tmp = s->buffer_size; 00420 if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) { 00421 av_log(h, AV_LOG_WARNING, "setsockopt(SO_RECVBUF): %s\n", strerror(errno)); 00422 } 00423 /* make the socket non-blocking */ 00424 ff_socket_nonblock(udp_fd, 1); 00425 } 00426 if (s->is_connected) { 00427 if (connect(udp_fd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len)) { 00428 av_log(h, AV_LOG_ERROR, "connect: %s\n", strerror(errno)); 00429 goto fail; 00430 } 00431 } 00432 00433 s->udp_fd = udp_fd; 00434 return 0; 00435 fail: 00436 if (udp_fd >= 0) 00437 closesocket(udp_fd); 00438 av_free(s); 00439 return AVERROR(EIO); 00440 } 00441 00442 static int udp_read(URLContext *h, uint8_t *buf, int size) 00443 { 00444 UDPContext *s = h->priv_data; 00445 int ret; 00446 00447 if (!(h->flags & AVIO_FLAG_NONBLOCK)) { 00448 ret = ff_network_wait_fd(s->udp_fd, 0); 00449 if (ret < 0) 00450 return ret; 00451 } 00452 ret = recv(s->udp_fd, buf, size, 0); 00453 return ret < 0 ? ff_neterrno() : ret; 00454 } 00455 00456 static int udp_write(URLContext *h, const uint8_t *buf, int size) 00457 { 00458 UDPContext *s = h->priv_data; 00459 int ret; 00460 00461 if (!(h->flags & AVIO_FLAG_NONBLOCK)) { 00462 ret = ff_network_wait_fd(s->udp_fd, 1); 00463 if (ret < 0) 00464 return ret; 00465 } 00466 00467 if (!s->is_connected) { 00468 ret = sendto (s->udp_fd, buf, size, 0, 00469 (struct sockaddr *) &s->dest_addr, 00470 s->dest_addr_len); 00471 } else 00472 ret = send(s->udp_fd, buf, size, 0); 00473 00474 return ret < 0 ? ff_neterrno() : ret; 00475 } 00476 00477 static int udp_close(URLContext *h) 00478 { 00479 UDPContext *s = h->priv_data; 00480 00481 if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) 00482 udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr); 00483 closesocket(s->udp_fd); 00484 av_free(s); 00485 return 0; 00486 } 00487 00488 URLProtocol ff_udp_protocol = { 00489 .name = "udp", 00490 .url_open = udp_open, 00491 .url_read = udp_read, 00492 .url_write = udp_write, 00493 .url_close = udp_close, 00494 .url_get_file_handle = udp_get_file_handle, 00495 };