Select has limitations on the fd values it could accept and silently
breaks when it is reached.
(cherry picked from commit a8475bbdb6)
tags/n0.8
| @@ -236,7 +236,6 @@ int ff_socket_nonblock(int socket, int enable) | |||
| } | |||
| #endif /* CONFIG_NETWORK */ | |||
| #if CONFIG_FFSERVER | |||
| #if !HAVE_POLL_H | |||
| int poll(struct pollfd *fds, nfds_t numfds, int timeout) | |||
| { | |||
| @@ -305,5 +304,3 @@ int poll(struct pollfd *fds, nfds_t numfds, int timeout) | |||
| return rc; | |||
| } | |||
| #endif /* HAVE_POLL_H */ | |||
| #endif /* CONFIG_FFSERVER */ | |||
| @@ -34,8 +34,8 @@ | |||
| #include "network.h" | |||
| #include "os_support.h" | |||
| #include <fcntl.h> | |||
| #if HAVE_SYS_SELECT_H | |||
| #include <sys/select.h> | |||
| #if HAVE_POLL_H | |||
| #include <sys/poll.h> | |||
| #endif | |||
| #include <sys/time.h> | |||
| @@ -221,9 +221,9 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size) | |||
| RTPContext *s = h->priv_data; | |||
| struct sockaddr_storage from; | |||
| socklen_t from_len; | |||
| int len, fd_max, n; | |||
| fd_set rfds; | |||
| struct timeval tv; | |||
| int len, n; | |||
| struct pollfd p[2] = {{s->rtp_fd, POLLIN, 0}, {s->rtcp_fd, POLLIN, 0}}; | |||
| #if 0 | |||
| for(;;) { | |||
| from_len = sizeof(from); | |||
| @@ -242,18 +242,10 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size) | |||
| if (url_interrupt_cb()) | |||
| return AVERROR(EINTR); | |||
| /* build fdset to listen to RTP and RTCP packets */ | |||
| FD_ZERO(&rfds); | |||
| fd_max = s->rtp_fd; | |||
| FD_SET(s->rtp_fd, &rfds); | |||
| if (s->rtcp_fd > fd_max) | |||
| fd_max = s->rtcp_fd; | |||
| FD_SET(s->rtcp_fd, &rfds); | |||
| tv.tv_sec = 0; | |||
| tv.tv_usec = 100 * 1000; | |||
| n = select(fd_max + 1, &rfds, NULL, NULL, &tv); | |||
| n = poll(p, 2, 100); | |||
| if (n > 0) { | |||
| /* first try RTCP */ | |||
| if (FD_ISSET(s->rtcp_fd, &rfds)) { | |||
| if (p[1].revents & POLLIN) { | |||
| from_len = sizeof(from); | |||
| len = recvfrom (s->rtcp_fd, buf, size, 0, | |||
| (struct sockaddr *)&from, &from_len); | |||
| @@ -266,7 +258,7 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size) | |||
| break; | |||
| } | |||
| /* then RTP */ | |||
| if (FD_ISSET(s->rtp_fd, &rfds)) { | |||
| if (p[0].revents & POLLIN) { | |||
| from_len = sizeof(from); | |||
| len = recvfrom (s->rtp_fd, buf, size, 0, | |||
| (struct sockaddr *)&from, &from_len); | |||
| @@ -26,8 +26,8 @@ | |||
| #include "avformat.h" | |||
| #include <sys/time.h> | |||
| #if HAVE_SYS_SELECT_H | |||
| #include <sys/select.h> | |||
| #if HAVE_POLL_H | |||
| #include <poll.h> | |||
| #endif | |||
| #include <strings.h> | |||
| #include "internal.h" | |||
| @@ -44,11 +44,11 @@ | |||
| //#define DEBUG | |||
| //#define DEBUG_RTP_TCP | |||
| /* Timeout values for socket select, in ms, | |||
| /* Timeout values for socket poll, in ms, | |||
| * and read_packet(), in seconds */ | |||
| #define SELECT_TIMEOUT_MS 100 | |||
| #define POLL_TIMEOUT_MS 100 | |||
| #define READ_PACKET_TIMEOUT_S 10 | |||
| #define MAX_TIMEOUTS READ_PACKET_TIMEOUT_S * 1000 / SELECT_TIMEOUT_MS | |||
| #define MAX_TIMEOUTS READ_PACKET_TIMEOUT_S * 1000 / POLL_TIMEOUT_MS | |||
| #define SDP_MAX_SIZE 16384 | |||
| #define RECVBUF_SIZE 10 * RTP_MAX_PACKET_LENGTH | |||
| @@ -429,8 +429,14 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, | |||
| } | |||
| } | |||
| /** | |||
| * Parse the sdp description and allocate the rtp streams and the | |||
| * pollfd array used for udp ones. | |||
| */ | |||
| int ff_sdp_parse(AVFormatContext *s, const char *content) | |||
| { | |||
| RTSPState *rt = s->priv_data; | |||
| const char *p; | |||
| int letter; | |||
| /* Some SDP lines, particularly for Realmedia or ASF RTSP streams, | |||
| @@ -470,6 +476,8 @@ int ff_sdp_parse(AVFormatContext *s, const char *content) | |||
| if (*p == '\n') | |||
| p++; | |||
| } | |||
| rt->p = av_malloc(sizeof(struct pollfd)*2*(rt->nb_rtsp_streams+1)); | |||
| if (!rt->p) return AVERROR(ENOMEM); | |||
| return 0; | |||
| } | |||
| #endif /* CONFIG_RTPDEC */ | |||
| @@ -531,6 +539,7 @@ void ff_rtsp_close_streams(AVFormatContext *s) | |||
| av_close_input_stream (rt->asf_ctx); | |||
| rt->asf_ctx = NULL; | |||
| } | |||
| av_free(rt->p); | |||
| av_free(rt->recvbuf); | |||
| } | |||
| @@ -1554,55 +1563,51 @@ static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, | |||
| { | |||
| RTSPState *rt = s->priv_data; | |||
| RTSPStream *rtsp_st; | |||
| fd_set rfds; | |||
| int fd, fd_rtcp, fd_max, n, i, ret, tcp_fd, timeout_cnt = 0; | |||
| struct timeval tv; | |||
| int n, i, ret, tcp_fd, timeout_cnt = 0; | |||
| int max_p = 0; | |||
| struct pollfd *p = rt->p; | |||
| for (;;) { | |||
| if (url_interrupt_cb()) | |||
| return AVERROR(EINTR); | |||
| if (wait_end && wait_end - av_gettime() < 0) | |||
| return AVERROR(EAGAIN); | |||
| FD_ZERO(&rfds); | |||
| max_p = 0; | |||
| if (rt->rtsp_hd) { | |||
| tcp_fd = fd_max = url_get_file_handle(rt->rtsp_hd); | |||
| FD_SET(tcp_fd, &rfds); | |||
| tcp_fd = url_get_file_handle(rt->rtsp_hd); | |||
| p[max_p].fd = tcp_fd; | |||
| p[max_p++].events = POLLIN; | |||
| } else { | |||
| fd_max = 0; | |||
| tcp_fd = -1; | |||
| } | |||
| for (i = 0; i < rt->nb_rtsp_streams; i++) { | |||
| rtsp_st = rt->rtsp_streams[i]; | |||
| if (rtsp_st->rtp_handle) { | |||
| fd = url_get_file_handle(rtsp_st->rtp_handle); | |||
| fd_rtcp = rtp_get_rtcp_file_handle(rtsp_st->rtp_handle); | |||
| if (FFMAX(fd, fd_rtcp) > fd_max) | |||
| fd_max = FFMAX(fd, fd_rtcp); | |||
| FD_SET(fd, &rfds); | |||
| FD_SET(fd_rtcp, &rfds); | |||
| p[max_p].fd = url_get_file_handle(rtsp_st->rtp_handle); | |||
| p[max_p++].events = POLLIN; | |||
| p[max_p].fd = rtp_get_rtcp_file_handle(rtsp_st->rtp_handle); | |||
| p[max_p++].events = POLLIN; | |||
| } | |||
| } | |||
| tv.tv_sec = 0; | |||
| tv.tv_usec = SELECT_TIMEOUT_MS * 1000; | |||
| n = select(fd_max + 1, &rfds, NULL, NULL, &tv); | |||
| n = poll(p, max_p, POLL_TIMEOUT_MS); | |||
| if (n > 0) { | |||
| int j = 1 - (tcp_fd == -1); | |||
| timeout_cnt = 0; | |||
| for (i = 0; i < rt->nb_rtsp_streams; i++) { | |||
| rtsp_st = rt->rtsp_streams[i]; | |||
| if (rtsp_st->rtp_handle) { | |||
| fd = url_get_file_handle(rtsp_st->rtp_handle); | |||
| fd_rtcp = rtp_get_rtcp_file_handle(rtsp_st->rtp_handle); | |||
| if (FD_ISSET(fd_rtcp, &rfds) || FD_ISSET(fd, &rfds)) { | |||
| if (p[j].revents & POLLIN || p[j+1].revents & POLLIN) { | |||
| ret = url_read(rtsp_st->rtp_handle, buf, buf_size); | |||
| if (ret > 0) { | |||
| *prtsp_st = rtsp_st; | |||
| return ret; | |||
| } | |||
| } | |||
| j+=2; | |||
| } | |||
| } | |||
| #if CONFIG_RTSP_DEMUXER | |||
| if (tcp_fd != -1 && FD_ISSET(tcp_fd, &rfds)) { | |||
| if (tcp_fd != -1 && p[0].revents & POLLIN) { | |||
| RTSPMessageHeader reply; | |||
| ret = ff_rtsp_read_reply(s, &reply, NULL, 0, NULL); | |||
| @@ -326,6 +326,11 @@ typedef struct RTSPState { | |||
| * The number of returned packets | |||
| */ | |||
| uint64_t packets; | |||
| /** | |||
| * Polling array for udp | |||
| */ | |||
| struct pollfd *p; | |||
| } RTSPState; | |||
| /** | |||
| @@ -22,8 +22,8 @@ | |||
| #include "avformat.h" | |||
| #include <sys/time.h> | |||
| #if HAVE_SYS_SELECT_H | |||
| #include <sys/select.h> | |||
| #if HAVE_POLL_H | |||
| #include <poll.h> | |||
| #endif | |||
| #include "network.h" | |||
| #include "rtsp.h" | |||
| @@ -172,23 +172,16 @@ static int rtsp_write_packet(AVFormatContext *s, AVPacket *pkt) | |||
| { | |||
| RTSPState *rt = s->priv_data; | |||
| RTSPStream *rtsp_st; | |||
| fd_set rfds; | |||
| int n, tcp_fd; | |||
| struct timeval tv; | |||
| int n; | |||
| struct pollfd p = {url_get_file_handle(rt->rtsp_hd), POLLIN, 0}; | |||
| AVFormatContext *rtpctx; | |||
| int ret; | |||
| tcp_fd = url_get_file_handle(rt->rtsp_hd); | |||
| while (1) { | |||
| FD_ZERO(&rfds); | |||
| FD_SET(tcp_fd, &rfds); | |||
| tv.tv_sec = 0; | |||
| tv.tv_usec = 0; | |||
| n = select(tcp_fd + 1, &rfds, NULL, NULL, &tv); | |||
| n = poll(&p, 1, 0); | |||
| if (n <= 0) | |||
| break; | |||
| if (FD_ISSET(tcp_fd, &rfds)) { | |||
| if (p.revents & POLLIN) { | |||
| RTSPMessageHeader reply; | |||
| /* Don't let ff_rtsp_read_reply handle interleaved packets, | |||
| @@ -25,8 +25,8 @@ | |||
| #include "network.h" | |||
| #include "os_support.h" | |||
| #include "internal.h" | |||
| #if HAVE_SYS_SELECT_H | |||
| #include <sys/select.h> | |||
| #if HAVE_POLL_H | |||
| #include <poll.h> | |||
| #endif | |||
| #include <sys/time.h> | |||
| @@ -183,19 +183,15 @@ static int sap_fetch_packet(AVFormatContext *s, AVPacket *pkt) | |||
| struct SAPState *sap = s->priv_data; | |||
| int fd = url_get_file_handle(sap->ann_fd); | |||
| int n, ret; | |||
| fd_set rfds; | |||
| struct timeval tv; | |||
| struct pollfd p = {fd, POLLIN, 0}; | |||
| uint8_t recvbuf[1500]; | |||
| if (sap->eof) | |||
| return AVERROR_EOF; | |||
| while (1) { | |||
| FD_ZERO(&rfds); | |||
| FD_SET(fd, &rfds); | |||
| tv.tv_sec = tv.tv_usec = 0; | |||
| n = select(fd + 1, &rfds, NULL, NULL, &tv); | |||
| if (n <= 0 || !FD_ISSET(fd, &rfds)) | |||
| n = poll(&p, 1, 0); | |||
| if (n <= 0 || !(p.revents & POLLIN)) | |||
| break; | |||
| ret = url_read(sap->ann_fd, recvbuf, sizeof(recvbuf)); | |||
| if (ret >= 8) { | |||
| @@ -23,8 +23,8 @@ | |||
| #include "internal.h" | |||
| #include "network.h" | |||
| #include "os_support.h" | |||
| #if HAVE_SYS_SELECT_H | |||
| #include <sys/select.h> | |||
| #if HAVE_POLL_H | |||
| #include <poll.h> | |||
| #endif | |||
| #include <sys/time.h> | |||
| @@ -38,9 +38,7 @@ static int tcp_open(URLContext *h, const char *uri, int flags) | |||
| struct addrinfo hints, *ai, *cur_ai; | |||
| int port, fd = -1; | |||
| TCPContext *s = NULL; | |||
| fd_set wfds, efds; | |||
| int fd_max, ret; | |||
| struct timeval tv; | |||
| int ret; | |||
| socklen_t optlen; | |||
| char hostname[1024],proto[1024],path[1024]; | |||
| char portstr[10]; | |||
| @@ -73,6 +71,7 @@ static int tcp_open(URLContext *h, const char *uri, int flags) | |||
| redo: | |||
| ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); | |||
| if (ret < 0) { | |||
| struct pollfd p = {fd, POLLOUT, 0}; | |||
| if (ff_neterrno() == FF_NETERROR(EINTR)) { | |||
| if (url_interrupt_cb()) | |||
| goto fail1; | |||
| @@ -88,15 +87,8 @@ static int tcp_open(URLContext *h, const char *uri, int flags) | |||
| ret = AVERROR(EINTR); | |||
| goto fail1; | |||
| } | |||
| fd_max = fd; | |||
| FD_ZERO(&wfds); | |||
| FD_ZERO(&efds); | |||
| FD_SET(fd, &wfds); | |||
| FD_SET(fd, &efds); | |||
| tv.tv_sec = 0; | |||
| tv.tv_usec = 100 * 1000; | |||
| ret = select(fd_max + 1, NULL, &wfds, &efds, &tv); | |||
| if (ret > 0 && (FD_ISSET(fd, &wfds) || FD_ISSET(fd, &efds))) | |||
| ret = poll(&p, 1, 100); | |||
| if (ret > 0) | |||
| break; | |||
| } | |||
| @@ -140,20 +132,14 @@ static int tcp_open(URLContext *h, const char *uri, int flags) | |||
| static int tcp_read(URLContext *h, uint8_t *buf, int size) | |||
| { | |||
| TCPContext *s = h->priv_data; | |||
| int len, fd_max, ret; | |||
| fd_set rfds; | |||
| struct timeval tv; | |||
| struct pollfd p = {s->fd, POLLIN, 0}; | |||
| int len, ret; | |||
| for (;;) { | |||
| if (url_interrupt_cb()) | |||
| return AVERROR(EINTR); | |||
| fd_max = s->fd; | |||
| FD_ZERO(&rfds); | |||
| FD_SET(s->fd, &rfds); | |||
| tv.tv_sec = 0; | |||
| tv.tv_usec = 100 * 1000; | |||
| ret = select(fd_max + 1, &rfds, NULL, NULL, &tv); | |||
| if (ret > 0 && FD_ISSET(s->fd, &rfds)) { | |||
| ret = poll(&p, 1, 100); | |||
| if (ret == 1 && p.revents & POLLIN) { | |||
| len = recv(s->fd, buf, size, 0); | |||
| if (len < 0) { | |||
| if (ff_neterrno() != FF_NETERROR(EINTR) && | |||
| @@ -171,21 +157,15 @@ static int tcp_read(URLContext *h, uint8_t *buf, int size) | |||
| static int tcp_write(URLContext *h, const uint8_t *buf, int size) | |||
| { | |||
| TCPContext *s = h->priv_data; | |||
| int ret, size1, fd_max, len; | |||
| fd_set wfds; | |||
| struct timeval tv; | |||
| int ret, size1, len; | |||
| struct pollfd p = {s->fd, POLLOUT, 0}; | |||
| size1 = size; | |||
| while (size > 0) { | |||
| if (url_interrupt_cb()) | |||
| return AVERROR(EINTR); | |||
| fd_max = s->fd; | |||
| FD_ZERO(&wfds); | |||
| FD_SET(s->fd, &wfds); | |||
| tv.tv_sec = 0; | |||
| tv.tv_usec = 100 * 1000; | |||
| ret = select(fd_max + 1, NULL, &wfds, NULL, &tv); | |||
| if (ret > 0 && FD_ISSET(s->fd, &wfds)) { | |||
| ret = poll(&p, 1, 100); | |||
| if (ret == 1 && p.revents & POLLOUT) { | |||
| len = send(s->fd, buf, size, 0); | |||
| if (len < 0) { | |||
| if (ff_neterrno() != FF_NETERROR(EINTR) && | |||
| @@ -31,8 +31,8 @@ | |||
| #include "internal.h" | |||
| #include "network.h" | |||
| #include "os_support.h" | |||
| #if HAVE_SYS_SELECT_H | |||
| #include <sys/select.h> | |||
| #if HAVE_POLL_H | |||
| #include <poll.h> | |||
| #endif | |||
| #include <sys/time.h> | |||
| @@ -432,25 +432,20 @@ 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; | |||
| struct pollfd p = {s->udp_fd, POLLIN, 0}; | |||
| 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); | |||
| ret = poll(&p, 1, 100); | |||
| if (ret < 0) { | |||
| if (ff_neterrno() == FF_NETERROR(EINTR)) | |||
| continue; | |||
| return AVERROR(EIO); | |||
| } | |||
| if (!(ret > 0 && FD_ISSET(s->udp_fd, &rfds))) | |||
| if (!(ret == 1 && p.revents & POLLIN)) | |||
| continue; | |||
| len = recv(s->udp_fd, buf, size, 0); | |||
| if (len < 0) { | |||