X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fudp.c;h=8bb63c629808abe8e60e3b790af43d6844d845bf;hb=32a659c758bf2ddd8ad48f18c06fa77444341286;hp=76a0f3509923f121e0bad22ef7dbae1f446bc81e;hpb=c76374c6db5f486672f9df223f43e4892bd655c9;p=ffmpeg diff --git a/libavformat/udp.c b/libavformat/udp.c index 76a0f350992..8bb63c62980 100644 --- a/libavformat/udp.c +++ b/libavformat/udp.c @@ -2,20 +2,20 @@ * UDP prototype streaming system * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * - * This file is part of FFmpeg. + * This file is part of Libav. * - * FFmpeg is free software; you can redistribute it and/or + * Libav is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * FFmpeg is distributed in the hope that it will be useful, + * Libav is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software + * License along with Libav; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -25,16 +25,16 @@ */ #define _BSD_SOURCE /* Needed for using struct ip_mreq with recent glibc */ -#define _DARWIN_C_SOURCE /* Needed for using IP_MULTICAST_TTL on OS X */ + #include "avformat.h" +#include "avio_internal.h" #include "libavutil/parseutils.h" +#include "libavutil/avstring.h" #include #include "internal.h" #include "network.h" #include "os_support.h" -#if HAVE_POLL_H -#include -#endif +#include "url.h" #include #ifndef IPV6_ADD_MEMBERSHIP @@ -179,8 +179,8 @@ static int udp_set_url(struct sockaddr_storage *addr, return addr_len; } -static int udp_socket_create(UDPContext *s, - struct sockaddr_storage *addr, int *addr_len) +static int udp_socket_create(UDPContext *s, struct sockaddr_storage *addr, + int *addr_len, const char *localaddr) { int udp_fd = -1; struct addrinfo *res0 = NULL, *res = NULL; @@ -188,7 +188,8 @@ static int udp_socket_create(UDPContext *s, if (((struct sockaddr *) &s->dest_addr)->sa_family) family = ((struct sockaddr *) &s->dest_addr)->sa_family; - res0 = udp_resolve_host(0, s->local_port, SOCK_DGRAM, family, AI_PASSIVE); + res0 = udp_resolve_host(localaddr[0] ? localaddr : NULL, s->local_port, + SOCK_DGRAM, family, AI_PASSIVE); if (res0 == 0) goto fail; for (res = res0; res; res=res->ai_next) { @@ -243,7 +244,7 @@ static int udp_port(struct sockaddr_storage *addr, int addr_len) * @param uri of the remote server * @return zero if no error. */ -int udp_set_remote_url(URLContext *h, const char *uri) +int ff_udp_set_remote_url(URLContext *h, const char *uri) { UDPContext *s = h->priv_data; char hostname[256], buf[10]; @@ -267,7 +268,7 @@ int udp_set_remote_url(URLContext *h, const char *uri) if (connect(s->udp_fd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len)) { s->is_connected = 0; - av_log(NULL, AV_LOG_ERROR, "connect: %s\n", strerror(errno)); + av_log(h, AV_LOG_ERROR, "connect: %s\n", strerror(errno)); return AVERROR(EIO); } } @@ -282,7 +283,7 @@ int udp_set_remote_url(URLContext *h, const char *uri) * @param h media file context * @return the local port number */ -int udp_get_local_port(URLContext *h) +int ff_udp_get_local_port(URLContext *h) { UDPContext *s = h->priv_data; return s->local_port; @@ -293,10 +294,7 @@ int udp_get_local_port(URLContext *h) * streams at the same time. * @param h media file context */ -#if !FF_API_UDP_GET_FILE -static -#endif -int udp_get_file_handle(URLContext *h) +static int udp_get_file_handle(URLContext *h) { UDPContext *s = h->priv_data; return s->udp_fd; @@ -306,9 +304,9 @@ int udp_get_file_handle(URLContext *h) /* return non zero if error */ static int udp_open(URLContext *h, const char *uri, int flags) { - char hostname[1024]; + char hostname[1024], localaddr[1024] = ""; int port, udp_fd = -1, tmp, bind_ret = -1; - UDPContext *s = NULL; + UDPContext *s = h->priv_data; int is_output; const char *p; char buf[256]; @@ -319,20 +317,15 @@ static int udp_open(URLContext *h, const char *uri, int flags) h->is_streamed = 1; h->max_packet_size = 1472; - is_output = (flags & URL_WRONLY); + is_output = !(flags & AVIO_FLAG_READ); - s = av_mallocz(sizeof(UDPContext)); - if (!s) - return AVERROR(ENOMEM); - - h->priv_data = s; s->ttl = 16; s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE; p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "reuse", p)) { - const char *endptr=NULL; + char *endptr = NULL; s->reuse_socket = strtol(buf, &endptr, 10); /* assume if no digits were found it is a request to enable it */ if (buf == endptr) @@ -354,6 +347,9 @@ static int udp_open(URLContext *h, const char *uri, int flags) if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { s->is_connected = strtol(buf, NULL, 10); } + if (av_find_info_tag(buf, sizeof(buf), "localaddr", p)) { + av_strlcpy(localaddr, buf, sizeof(localaddr)); + } } /* fill the dest addr */ @@ -362,21 +358,21 @@ static int udp_open(URLContext *h, const char *uri, int flags) /* XXX: fix av_url_split */ if (hostname[0] == '\0' || hostname[0] == '?') { /* only accepts null hostname if input */ - if (flags & URL_WRONLY) + if (!(flags & AVIO_FLAG_READ)) goto fail; } else { - if (udp_set_remote_url(h, uri) < 0) + if (ff_udp_set_remote_url(h, uri) < 0) goto fail; } - if (s->is_multicast && !(h->flags & URL_WRONLY)) + if ((s->is_multicast || !s->local_port) && (h->flags & AVIO_FLAG_READ)) s->local_port = port; - udp_fd = udp_socket_create(s, &my_addr, &len); + udp_fd = udp_socket_create(s, &my_addr, &len, localaddr); if (udp_fd < 0) goto fail; /* Follow the requested reuse option, unless it's multicast in which - * case enable reuse unless explicitely disabled. + * case enable reuse unless explicitly disabled. */ if (s->reuse_socket || (s->is_multicast && !reuse_specified)) { s->reuse_socket = 1; @@ -386,7 +382,7 @@ static int udp_open(URLContext *h, const char *uri, int flags) /* the bind is needed to give a port to the socket now */ /* if multicast, try the multicast address bind first */ - if (s->is_multicast && !(h->flags & URL_WRONLY)) { + if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) { bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len); } /* bind to the local address if not multicast or if the multicast @@ -399,7 +395,7 @@ static int udp_open(URLContext *h, const char *uri, int flags) s->local_port = udp_port(&my_addr, len); if (s->is_multicast) { - if (h->flags & URL_WRONLY) { + if (!(h->flags & AVIO_FLAG_READ)) { /* output */ if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0) goto fail; @@ -414,7 +410,7 @@ static int udp_open(URLContext *h, const char *uri, int flags) /* limit the tx buf size to limit latency */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) { - av_log(NULL, AV_LOG_ERROR, "setsockopt(SO_SNDBUF): %s\n", strerror(errno)); + av_log(h, AV_LOG_ERROR, "setsockopt(SO_SNDBUF): %s\n", strerror(errno)); goto fail; } } else { @@ -422,14 +418,14 @@ static int udp_open(URLContext *h, const char *uri, int flags) * avoid losing data on OSes that set this too low by default. */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) { - av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_RECVBUF): %s\n", strerror(errno)); + av_log(h, AV_LOG_WARNING, "setsockopt(SO_RECVBUF): %s\n", strerror(errno)); } /* make the socket non-blocking */ ff_socket_nonblock(udp_fd, 1); } if (s->is_connected) { if (connect(udp_fd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len)) { - av_log(NULL, AV_LOG_ERROR, "connect: %s\n", strerror(errno)); + av_log(h, AV_LOG_ERROR, "connect: %s\n", strerror(errno)); goto fail; } } @@ -439,38 +435,21 @@ static int udp_open(URLContext *h, const char *uri, int flags) fail: if (udp_fd >= 0) closesocket(udp_fd); - av_free(s); return AVERROR(EIO); } static int udp_read(URLContext *h, uint8_t *buf, int size) { UDPContext *s = h->priv_data; - struct pollfd p = {s->udp_fd, POLLIN, 0}; - int len; int ret; - for(;;) { - if (url_interrupt_cb()) - return AVERROR_EXIT; - ret = poll(&p, 1, 100); - if (ret < 0) { - if (ff_neterrno() == AVERROR(EINTR)) - continue; - return AVERROR(EIO); - } - if (!(ret == 1 && p.revents & POLLIN)) - continue; - len = recv(s->udp_fd, buf, size, 0); - if (len < 0) { - if (ff_neterrno() != AVERROR(EAGAIN) && - ff_neterrno() != AVERROR(EINTR)) - return AVERROR(EIO); - } else { - break; - } + if (!(h->flags & AVIO_FLAG_NONBLOCK)) { + ret = ff_network_wait_fd(s->udp_fd, 0); + if (ret < 0) + return ret; } - return len; + ret = recv(s->udp_fd, buf, size, 0); + return ret < 0 ? ff_neterrno() : ret; } static int udp_write(URLContext *h, const uint8_t *buf, int size) @@ -478,41 +457,39 @@ static int udp_write(URLContext *h, const uint8_t *buf, int size) UDPContext *s = h->priv_data; int ret; - for(;;) { - if (!s->is_connected) { - ret = sendto (s->udp_fd, buf, size, 0, - (struct sockaddr *) &s->dest_addr, - s->dest_addr_len); - } else - ret = send(s->udp_fd, buf, size, 0); - if (ret < 0) { - if (ff_neterrno() != AVERROR(EINTR) && - ff_neterrno() != AVERROR(EAGAIN)) - return ff_neterrno(); - } else { - break; - } + if (!(h->flags & AVIO_FLAG_NONBLOCK)) { + ret = ff_network_wait_fd(s->udp_fd, 1); + if (ret < 0) + return ret; } - return size; + + if (!s->is_connected) { + ret = sendto (s->udp_fd, buf, size, 0, + (struct sockaddr *) &s->dest_addr, + s->dest_addr_len); + } else + ret = send(s->udp_fd, buf, size, 0); + + return ret < 0 ? ff_neterrno() : ret; } static int udp_close(URLContext *h) { UDPContext *s = h->priv_data; - if (s->is_multicast && !(h->flags & URL_WRONLY)) + if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr); closesocket(s->udp_fd); - av_free(s); return 0; } URLProtocol ff_udp_protocol = { - "udp", - udp_open, - udp_read, - udp_write, - NULL, /* seek */ - udp_close, + .name = "udp", + .url_open = udp_open, + .url_read = udp_read, + .url_write = udp_write, + .url_close = udp_close, .url_get_file_handle = udp_get_file_handle, + .priv_data_size = sizeof(UDPContext), + .flags = URL_PROTOCOL_FLAG_NETWORK, };