00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00027 #define _BSD_SOURCE
00028
00029 #include "avformat.h"
00030 #include "avio_internal.h"
00031 #include "libavutil/parseutils.h"
00032 #include "libavutil/fifo.h"
00033 #include <unistd.h>
00034 #include "internal.h"
00035 #include "network.h"
00036 #include "os_support.h"
00037 #include "url.h"
00038
00039 #if HAVE_PTHREADS
00040 #include <pthread.h>
00041 #endif
00042
00043 #include <sys/time.h>
00044
00045 #ifndef IPV6_ADD_MEMBERSHIP
00046 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
00047 #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
00048 #endif
00049
00050 typedef struct {
00051 int udp_fd;
00052 int ttl;
00053 int buffer_size;
00054 int is_multicast;
00055 int local_port;
00056 int reuse_socket;
00057 struct sockaddr_storage dest_addr;
00058 int dest_addr_len;
00059 int is_connected;
00060
00061
00062 int circular_buffer_size;
00063 AVFifoBuffer *fifo;
00064 int circular_buffer_error;
00065 #if HAVE_PTHREADS
00066 pthread_t circular_buffer_thread;
00067 #endif
00068 } UDPContext;
00069
00070 #define UDP_TX_BUF_SIZE 32768
00071 #define UDP_MAX_PKT_SIZE 65536
00072
00073 static int udp_set_multicast_ttl(int sockfd, int mcastTTL,
00074 struct sockaddr *addr)
00075 {
00076 #ifdef IP_MULTICAST_TTL
00077 if (addr->sa_family == AF_INET) {
00078 if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &mcastTTL, sizeof(mcastTTL)) < 0) {
00079 av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_TTL): %s\n", strerror(errno));
00080 return -1;
00081 }
00082 }
00083 #endif
00084 #if defined(IPPROTO_IPV6) && defined(IPV6_MULTICAST_HOPS)
00085 if (addr->sa_family == AF_INET6) {
00086 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastTTL, sizeof(mcastTTL)) < 0) {
00087 av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_HOPS): %s\n", strerror(errno));
00088 return -1;
00089 }
00090 }
00091 #endif
00092 return 0;
00093 }
00094
00095 static int udp_join_multicast_group(int sockfd, struct sockaddr *addr)
00096 {
00097 #ifdef IP_ADD_MEMBERSHIP
00098 if (addr->sa_family == AF_INET) {
00099 struct ip_mreq mreq;
00100
00101 mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
00102 mreq.imr_interface.s_addr= INADDR_ANY;
00103 if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
00104 av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno));
00105 return -1;
00106 }
00107 }
00108 #endif
00109 #if HAVE_STRUCT_IPV6_MREQ && defined(IPPROTO_IPV6)
00110 if (addr->sa_family == AF_INET6) {
00111 struct ipv6_mreq mreq6;
00112
00113 memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
00114 mreq6.ipv6mr_interface= 0;
00115 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
00116 av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP): %s\n", strerror(errno));
00117 return -1;
00118 }
00119 }
00120 #endif
00121 return 0;
00122 }
00123
00124 static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr)
00125 {
00126 #ifdef IP_DROP_MEMBERSHIP
00127 if (addr->sa_family == AF_INET) {
00128 struct ip_mreq mreq;
00129
00130 mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
00131 mreq.imr_interface.s_addr= INADDR_ANY;
00132 if (setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
00133 av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_DROP_MEMBERSHIP): %s\n", strerror(errno));
00134 return -1;
00135 }
00136 }
00137 #endif
00138 #if HAVE_STRUCT_IPV6_MREQ && defined(IPPROTO_IPV6)
00139 if (addr->sa_family == AF_INET6) {
00140 struct ipv6_mreq mreq6;
00141
00142 memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
00143 mreq6.ipv6mr_interface= 0;
00144 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
00145 av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP): %s\n", strerror(errno));
00146 return -1;
00147 }
00148 }
00149 #endif
00150 return 0;
00151 }
00152
00153 static struct addrinfo* udp_resolve_host(const char *hostname, int port,
00154 int type, int family, int flags)
00155 {
00156 struct addrinfo hints, *res = 0;
00157 int error;
00158 char sport[16];
00159 const char *node = 0, *service = "0";
00160
00161 if (port > 0) {
00162 snprintf(sport, sizeof(sport), "%d", port);
00163 service = sport;
00164 }
00165 if ((hostname) && (hostname[0] != '\0') && (hostname[0] != '?')) {
00166 node = hostname;
00167 }
00168 memset(&hints, 0, sizeof(hints));
00169 hints.ai_socktype = type;
00170 hints.ai_family = family;
00171 hints.ai_flags = flags;
00172 if ((error = getaddrinfo(node, service, &hints, &res))) {
00173 res = NULL;
00174 av_log(NULL, AV_LOG_ERROR, "udp_resolve_host: %s\n", gai_strerror(error));
00175 }
00176
00177 return res;
00178 }
00179
00180 static int udp_set_url(struct sockaddr_storage *addr,
00181 const char *hostname, int port)
00182 {
00183 struct addrinfo *res0;
00184 int addr_len;
00185
00186 res0 = udp_resolve_host(hostname, port, SOCK_DGRAM, AF_UNSPEC, 0);
00187 if (res0 == 0) return AVERROR(EIO);
00188 memcpy(addr, res0->ai_addr, res0->ai_addrlen);
00189 addr_len = res0->ai_addrlen;
00190 freeaddrinfo(res0);
00191
00192 return addr_len;
00193 }
00194
00195 static int udp_socket_create(UDPContext *s,
00196 struct sockaddr_storage *addr, int *addr_len)
00197 {
00198 int udp_fd = -1;
00199 struct addrinfo *res0 = NULL, *res = NULL;
00200 int family = AF_UNSPEC;
00201
00202 if (((struct sockaddr *) &s->dest_addr)->sa_family)
00203 family = ((struct sockaddr *) &s->dest_addr)->sa_family;
00204 res0 = udp_resolve_host(0, s->local_port, SOCK_DGRAM, family, AI_PASSIVE);
00205 if (res0 == 0)
00206 goto fail;
00207 for (res = res0; res; res=res->ai_next) {
00208 udp_fd = socket(res->ai_family, SOCK_DGRAM, 0);
00209 if (udp_fd > 0) break;
00210 av_log(NULL, AV_LOG_ERROR, "socket: %s\n", strerror(errno));
00211 }
00212
00213 if (udp_fd < 0)
00214 goto fail;
00215
00216 memcpy(addr, res->ai_addr, res->ai_addrlen);
00217 *addr_len = res->ai_addrlen;
00218
00219 freeaddrinfo(res0);
00220
00221 return udp_fd;
00222
00223 fail:
00224 if (udp_fd >= 0)
00225 closesocket(udp_fd);
00226 if(res0)
00227 freeaddrinfo(res0);
00228 return -1;
00229 }
00230
00231 static int udp_port(struct sockaddr_storage *addr, int addr_len)
00232 {
00233 char sbuf[sizeof(int)*3+1];
00234
00235 if (getnameinfo((struct sockaddr *)addr, addr_len, NULL, 0, sbuf, sizeof(sbuf), NI_NUMERICSERV) != 0) {
00236 av_log(NULL, AV_LOG_ERROR, "getnameinfo: %s\n", strerror(errno));
00237 return -1;
00238 }
00239
00240 return strtol(sbuf, NULL, 10);
00241 }
00242
00243
00259 int ff_udp_set_remote_url(URLContext *h, const char *uri)
00260 {
00261 UDPContext *s = h->priv_data;
00262 char hostname[256], buf[10];
00263 int port;
00264 const char *p;
00265
00266 av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
00267
00268
00269 s->dest_addr_len = udp_set_url(&s->dest_addr, hostname, port);
00270 if (s->dest_addr_len < 0) {
00271 return AVERROR(EIO);
00272 }
00273 s->is_multicast = ff_is_multicast_address((struct sockaddr*) &s->dest_addr);
00274 p = strchr(uri, '?');
00275 if (p) {
00276 if (av_find_info_tag(buf, sizeof(buf), "connect", p)) {
00277 int was_connected = s->is_connected;
00278 s->is_connected = strtol(buf, NULL, 10);
00279 if (s->is_connected && !was_connected) {
00280 if (connect(s->udp_fd, (struct sockaddr *) &s->dest_addr,
00281 s->dest_addr_len)) {
00282 s->is_connected = 0;
00283 av_log(NULL, AV_LOG_ERROR, "connect: %s\n", strerror(errno));
00284 return AVERROR(EIO);
00285 }
00286 }
00287 }
00288 }
00289
00290 return 0;
00291 }
00292
00298 int ff_udp_get_local_port(URLContext *h)
00299 {
00300 UDPContext *s = h->priv_data;
00301 return s->local_port;
00302 }
00303
00309 #if !FF_API_UDP_GET_FILE
00310 static
00311 #endif
00312 int udp_get_file_handle(URLContext *h)
00313 {
00314 UDPContext *s = h->priv_data;
00315 return s->udp_fd;
00316 }
00317
00318 static void *circular_buffer_task( void *_URLContext)
00319 {
00320 URLContext *h = _URLContext;
00321 UDPContext *s = h->priv_data;
00322 fd_set rfds;
00323 struct timeval tv;
00324
00325 for(;;) {
00326 int left;
00327 int ret;
00328 int len;
00329
00330 if (url_interrupt_cb()) {
00331 s->circular_buffer_error = EINTR;
00332 return NULL;
00333 }
00334
00335 FD_ZERO(&rfds);
00336 FD_SET(s->udp_fd, &rfds);
00337 tv.tv_sec = 1;
00338 tv.tv_usec = 0;
00339 ret = select(s->udp_fd + 1, &rfds, NULL, NULL, &tv);
00340 if (ret < 0) {
00341 if (ff_neterrno() == AVERROR(EINTR))
00342 continue;
00343 s->circular_buffer_error = EIO;
00344 return NULL;
00345 }
00346
00347 if (!(ret > 0 && FD_ISSET(s->udp_fd, &rfds)))
00348 continue;
00349
00350
00351
00352 left = av_fifo_space(s->fifo);
00353 left = FFMIN(left, s->fifo->end - s->fifo->wptr);
00354
00355
00356 if( !left) {
00357 av_log(h, AV_LOG_ERROR, "circular_buffer: OVERRUN\n");
00358 s->circular_buffer_error = EIO;
00359 return NULL;
00360 }
00361
00362 len = recv(s->udp_fd, s->fifo->wptr, left, 0);
00363 if (len < 0) {
00364 if (ff_neterrno() != AVERROR(EAGAIN) && ff_neterrno() != AVERROR(EINTR)) {
00365 s->circular_buffer_error = EIO;
00366 return NULL;
00367 }
00368 }
00369 s->fifo->wptr += len;
00370 if (s->fifo->wptr >= s->fifo->end)
00371 s->fifo->wptr = s->fifo->buffer;
00372 s->fifo->wndx += len;
00373 }
00374
00375 return NULL;
00376 }
00377
00378
00379
00380 static int udp_open(URLContext *h, const char *uri, int flags)
00381 {
00382 char hostname[1024];
00383 int port, udp_fd = -1, tmp, bind_ret = -1;
00384 UDPContext *s = NULL;
00385 int is_output;
00386 const char *p;
00387 char buf[256];
00388 struct sockaddr_storage my_addr;
00389 int len;
00390 int reuse_specified = 0;
00391
00392 h->is_streamed = 1;
00393 h->max_packet_size = 1472;
00394
00395 is_output = (flags & AVIO_WRONLY);
00396
00397 s = av_mallocz(sizeof(UDPContext));
00398 if (!s)
00399 return AVERROR(ENOMEM);
00400
00401 h->priv_data = s;
00402 s->ttl = 16;
00403 s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE;
00404
00405 s->circular_buffer_size = 7*188*4096;
00406
00407 p = strchr(uri, '?');
00408 if (p) {
00409 if (av_find_info_tag(buf, sizeof(buf), "reuse", p)) {
00410 char *endptr=NULL;
00411 s->reuse_socket = strtol(buf, &endptr, 10);
00412
00413 if (buf == endptr)
00414 s->reuse_socket = 1;
00415 reuse_specified = 1;
00416 }
00417 if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) {
00418 s->ttl = strtol(buf, NULL, 10);
00419 }
00420 if (av_find_info_tag(buf, sizeof(buf), "localport", p)) {
00421 s->local_port = strtol(buf, NULL, 10);
00422 }
00423 if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
00424 h->max_packet_size = strtol(buf, NULL, 10);
00425 }
00426 if (av_find_info_tag(buf, sizeof(buf), "buffer_size", p)) {
00427 s->buffer_size = strtol(buf, NULL, 10);
00428 }
00429 if (av_find_info_tag(buf, sizeof(buf), "connect", p)) {
00430 s->is_connected = strtol(buf, NULL, 10);
00431 }
00432 if (av_find_info_tag(buf, sizeof(buf), "fifo_size", p)) {
00433 s->circular_buffer_size = strtol(buf, NULL, 10)*188;
00434 }
00435 }
00436
00437
00438 av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
00439
00440
00441 if (hostname[0] == '\0' || hostname[0] == '?') {
00442
00443 if (flags & AVIO_WRONLY)
00444 goto fail;
00445 } else {
00446 if (ff_udp_set_remote_url(h, uri) < 0)
00447 goto fail;
00448 }
00449
00450 if (s->is_multicast && !(h->flags & AVIO_WRONLY))
00451 s->local_port = port;
00452 udp_fd = udp_socket_create(s, &my_addr, &len);
00453 if (udp_fd < 0)
00454 goto fail;
00455
00456
00457
00458
00459 if (s->reuse_socket || (s->is_multicast && !reuse_specified)) {
00460 s->reuse_socket = 1;
00461 if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0)
00462 goto fail;
00463 }
00464
00465
00466
00467 if (s->is_multicast && !(h->flags & AVIO_WRONLY)) {
00468 bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len);
00469 }
00470
00471
00472 if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0)
00473 goto fail;
00474
00475 len = sizeof(my_addr);
00476 getsockname(udp_fd, (struct sockaddr *)&my_addr, &len);
00477 s->local_port = udp_port(&my_addr, len);
00478
00479 if (s->is_multicast) {
00480 if (h->flags & AVIO_WRONLY) {
00481
00482 if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0)
00483 goto fail;
00484 } else {
00485
00486 if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0)
00487 goto fail;
00488 }
00489 }
00490
00491 if (is_output) {
00492
00493 tmp = s->buffer_size;
00494 if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) {
00495 av_log(NULL, AV_LOG_ERROR, "setsockopt(SO_SNDBUF): %s\n", strerror(errno));
00496 goto fail;
00497 }
00498 } else {
00499
00500
00501 tmp = s->buffer_size;
00502 if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) {
00503 av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_RECVBUF): %s\n", strerror(errno));
00504 }
00505
00506 ff_socket_nonblock(udp_fd, 1);
00507 }
00508 if (s->is_connected) {
00509 if (connect(udp_fd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len)) {
00510 av_log(NULL, AV_LOG_ERROR, "connect: %s\n", strerror(errno));
00511 goto fail;
00512 }
00513 }
00514
00515 s->udp_fd = udp_fd;
00516
00517 #if HAVE_PTHREADS
00518 if (!is_output && s->circular_buffer_size) {
00519
00520 s->fifo = av_fifo_alloc(s->circular_buffer_size);
00521 if (pthread_create(&s->circular_buffer_thread, NULL, circular_buffer_task, h)) {
00522 av_log(h, AV_LOG_ERROR, "pthread_create failed\n");
00523 goto fail;
00524 }
00525 }
00526 #endif
00527
00528 return 0;
00529 fail:
00530 if (udp_fd >= 0)
00531 closesocket(udp_fd);
00532 av_fifo_free(s->fifo);
00533 av_free(s);
00534 return AVERROR(EIO);
00535 }
00536
00537 static int udp_read(URLContext *h, uint8_t *buf, int size)
00538 {
00539 UDPContext *s = h->priv_data;
00540 int ret;
00541 int avail;
00542 fd_set rfds;
00543 struct timeval tv;
00544
00545 if (s->fifo) {
00546
00547 do {
00548 avail = av_fifo_size(s->fifo);
00549 if (avail) {
00550
00551
00552 size = FFMIN( avail, size);
00553 av_fifo_generic_read(s->fifo, buf, size, NULL);
00554 return size;
00555 }
00556 else {
00557 FD_ZERO(&rfds);
00558 FD_SET(s->udp_fd, &rfds);
00559 tv.tv_sec = 1;
00560 tv.tv_usec = 0;
00561 ret = select(s->udp_fd + 1, &rfds, NULL, NULL, &tv);
00562 if (ret<0)
00563 return ret;
00564 }
00565 } while( 1);
00566 }
00567
00568 if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
00569 ret = ff_network_wait_fd(s->udp_fd, 0);
00570 if (ret < 0)
00571 return ret;
00572 }
00573 ret = recv(s->udp_fd, buf, size, 0);
00574
00575 return ret < 0 ? ff_neterrno() : ret;
00576 }
00577
00578 static int udp_write(URLContext *h, const uint8_t *buf, int size)
00579 {
00580 UDPContext *s = h->priv_data;
00581 int ret;
00582
00583 if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
00584 ret = ff_network_wait_fd(s->udp_fd, 1);
00585 if (ret < 0)
00586 return ret;
00587 }
00588
00589 if (!s->is_connected) {
00590 ret = sendto (s->udp_fd, buf, size, 0,
00591 (struct sockaddr *) &s->dest_addr,
00592 s->dest_addr_len);
00593 } else
00594 ret = send(s->udp_fd, buf, size, 0);
00595
00596 return ret < 0 ? ff_neterrno() : ret;
00597 }
00598
00599 static int udp_close(URLContext *h)
00600 {
00601 UDPContext *s = h->priv_data;
00602
00603 if (s->is_multicast && !(h->flags & AVIO_WRONLY))
00604 udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr);
00605 closesocket(s->udp_fd);
00606 av_fifo_free(s->fifo);
00607 av_free(s);
00608 return 0;
00609 }
00610
00611 URLProtocol ff_udp_protocol = {
00612 .name = "udp",
00613 .url_open = udp_open,
00614 .url_read = udp_read,
00615 .url_write = udp_write,
00616 .url_close = udp_close,
00617 .url_get_file_handle = udp_get_file_handle,
00618 };