X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fudp.c;h=d48d5417c75f1b7093462ea8a657ae202afbd7e4;hb=f27ac6d83c3d90cac49230480a8569a1651763bd;hp=8080c980451fab7e2f6727b3615cbfb8249c0033;hpb=66355be3c3eb8e797589058b0773f773a8c2231e;p=ffmpeg diff --git a/libavformat/udp.c b/libavformat/udp.c index 8080c980451..d48d5417c75 100644 --- a/libavformat/udp.c +++ b/libavformat/udp.c @@ -27,13 +27,13 @@ #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 #include "internal.h" #include "network.h" #include "os_support.h" -#if HAVE_SYS_SELECT_H -#include -#endif +#include "url.h" #include #ifndef IPV6_ADD_MEMBERSHIP @@ -242,7 +242,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]; @@ -259,14 +259,14 @@ int udp_set_remote_url(URLContext *h, const char *uri) s->is_multicast = ff_is_multicast_address((struct sockaddr*) &s->dest_addr); p = strchr(uri, '?'); if (p) { - if (find_info_tag(buf, sizeof(buf), "connect", p)) { + if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { int was_connected = s->is_connected; s->is_connected = strtol(buf, NULL, 10); if (s->is_connected && !was_connected) { 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); } } @@ -281,7 +281,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; @@ -292,10 +292,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; @@ -313,11 +310,12 @@ static int udp_open(URLContext *h, const char *uri, int flags) char buf[256]; struct sockaddr_storage my_addr; int len; + int reuse_specified = 0; h->is_streamed = 1; h->max_packet_size = 1472; - is_output = (flags & URL_WRONLY); + is_output = (flags & AVIO_FLAG_WRITE); s = av_mallocz(sizeof(UDPContext)); if (!s) @@ -329,20 +327,27 @@ static int udp_open(URLContext *h, const char *uri, int flags) p = strchr(uri, '?'); if (p) { - s->reuse_socket = find_info_tag(buf, sizeof(buf), "reuse", p); - if (find_info_tag(buf, sizeof(buf), "ttl", p)) { + if (av_find_info_tag(buf, sizeof(buf), "reuse", p)) { + const 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) + s->reuse_socket = 1; + reuse_specified = 1; + } + if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) { s->ttl = strtol(buf, NULL, 10); } - if (find_info_tag(buf, sizeof(buf), "localport", p)) { + if (av_find_info_tag(buf, sizeof(buf), "localport", p)) { s->local_port = strtol(buf, NULL, 10); } - if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) { + if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) { h->max_packet_size = strtol(buf, NULL, 10); } - if (find_info_tag(buf, sizeof(buf), "buffer_size", p)) { + if (av_find_info_tag(buf, sizeof(buf), "buffer_size", p)) { s->buffer_size = strtol(buf, NULL, 10); } - if (find_info_tag(buf, sizeof(buf), "connect", p)) { + if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { s->is_connected = strtol(buf, NULL, 10); } } @@ -353,26 +358,31 @@ 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_WRITE) 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 && !(h->flags & AVIO_FLAG_WRITE)) s->local_port = port; udp_fd = udp_socket_create(s, &my_addr, &len); if (udp_fd < 0) goto fail; - if (s->reuse_socket) + /* Follow the requested reuse option, unless it's multicast in which + * case enable reuse unless explicitely disabled. + */ + if (s->reuse_socket || (s->is_multicast && !reuse_specified)) { + s->reuse_socket = 1; if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0) goto fail; + } /* 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_WRITE)) { bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len); } /* bind to the local address if not multicast or if the multicast @@ -385,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_WRITE) { /* output */ if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0) goto fail; @@ -400,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 { @@ -408,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; } } @@ -432,36 +442,15 @@ static int udp_open(URLContext *h, const char *uri, int flags) static int udp_read(URLContext *h, uint8_t *buf, int size) { UDPContext *s = h->priv_data; - int len; - fd_set rfds; int ret; - struct timeval tv; - - for(;;) { - if (url_interrupt_cb()) - return AVERROR(EINTR); - FD_ZERO(&rfds); - FD_SET(s->udp_fd, &rfds); - tv.tv_sec = 0; - tv.tv_usec = 100 * 1000; - ret = select(s->udp_fd + 1, &rfds, NULL, NULL, &tv); - if (ret < 0) { - if (ff_neterrno() == FF_NETERROR(EINTR)) - continue; - return AVERROR(EIO); - } - if (!(ret > 0 && FD_ISSET(s->udp_fd, &rfds))) - continue; - len = recv(s->udp_fd, buf, size, 0); - if (len < 0) { - if (ff_neterrno() != FF_NETERROR(EAGAIN) && - ff_neterrno() != FF_NETERROR(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) @@ -469,29 +458,27 @@ 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() != FF_NETERROR(EINTR) && - ff_neterrno() != FF_NETERROR(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_WRITE)) udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr); closesocket(s->udp_fd); av_free(s); @@ -499,11 +486,10 @@ static int udp_close(URLContext *h) } 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, };