Document the functions and have both use a millisecond timeout and check for interrupt.tags/n2.0
| @@ -189,8 +189,29 @@ int ff_is_multicast_address(struct sockaddr *addr) | |||
| return 0; | |||
| } | |||
| static int ff_poll_interrupt(struct pollfd *p, nfds_t nfds, int timeout, | |||
| AVIOInterruptCB *cb) | |||
| { | |||
| int runs = timeout / POLLING_TIME; | |||
| int ret = 0; | |||
| do { | |||
| if (ff_check_interrupt(cb)) | |||
| return AVERROR_EXIT; | |||
| ret = poll(p, nfds, POLLING_TIME); | |||
| if (ret != 0) | |||
| break; | |||
| } while (timeout < 0 || runs-- > 0); | |||
| if (!ret) | |||
| return AVERROR(ETIMEDOUT); | |||
| if (ret < 0) | |||
| return AVERROR(errno); | |||
| return ret; | |||
| } | |||
| int ff_listen_bind(int fd, const struct sockaddr *addr, | |||
| socklen_t addrlen, int timeout) | |||
| socklen_t addrlen, int timeout, URLContext *h) | |||
| { | |||
| int ret; | |||
| int reuse = 1; | |||
| @@ -204,9 +225,9 @@ int ff_listen_bind(int fd, const struct sockaddr *addr, | |||
| if (ret) | |||
| return ff_neterrno(); | |||
| ret = poll(&lp, 1, timeout >= 0 ? timeout : -1); | |||
| if (ret <= 0) | |||
| return AVERROR(ETIMEDOUT); | |||
| ret = ff_poll_interrupt(&lp, 1, timeout, &h->interrupt_callback); | |||
| if (ret < 0) | |||
| return ret; | |||
| ret = accept(fd, NULL, NULL); | |||
| if (ret < 0) | |||
| @@ -236,15 +257,9 @@ int ff_listen_connect(int fd, const struct sockaddr *addr, | |||
| continue; | |||
| case AVERROR(EINPROGRESS): | |||
| case AVERROR(EAGAIN): | |||
| while (timeout--) { | |||
| if (ff_check_interrupt(&h->interrupt_callback)) | |||
| return AVERROR_EXIT; | |||
| ret = poll(&p, 1, 100); | |||
| if (ret > 0) | |||
| break; | |||
| } | |||
| if (ret <= 0) | |||
| return AVERROR(ETIMEDOUT); | |||
| ret = ff_poll_interrupt(&p, 1, timeout, &h->interrupt_callback); | |||
| if (ret < 0) | |||
| return ret; | |||
| optlen = sizeof(ret); | |||
| if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen)) | |||
| ret = AVUNERROR(ff_neterrno()); | |||
| @@ -210,9 +210,38 @@ const char *ff_gai_strerror(int ecode); | |||
| int ff_is_multicast_address(struct sockaddr *addr); | |||
| #define POLLING_TIME 100 /// Time in milliseconds between interrupt check | |||
| /** | |||
| * Bind to a file descriptor and poll for a connection. | |||
| * | |||
| * @param fd First argument of bind(). | |||
| * @param addr Second argument of bind(). | |||
| * @param addrlen Third argument of bind(). | |||
| * @param timeout Polling timeout in milliseconds. | |||
| * @param h URLContext providing interrupt check | |||
| * callback and logging context. | |||
| * @return A non-blocking file descriptor on success | |||
| * or an AVERROR on failure. | |||
| */ | |||
| int ff_listen_bind(int fd, const struct sockaddr *addr, | |||
| socklen_t addrlen, int timeout); | |||
| socklen_t addrlen, int timeout, | |||
| URLContext *h); | |||
| /** | |||
| * Connect to a file descriptor and poll for result. | |||
| * | |||
| * @param fd First argument of connect(), | |||
| * will be set as non-blocking. | |||
| * @param addr Second argument of connect(). | |||
| * @param addrlen Third argument of connect(). | |||
| * @param timeout Polling timeout in milliseconds. | |||
| * @param h URLContext providing interrupt check | |||
| * callback and logging context. | |||
| * @return 0 on success, AVERROR on failure. | |||
| */ | |||
| int ff_listen_connect(int fd, const struct sockaddr *addr, | |||
| socklen_t addrlen, int timeout, | |||
| URLContext *h); | |||
| #endif /* AVFORMAT_NETWORK_H */ | |||
| @@ -92,13 +92,13 @@ static int tcp_open(URLContext *h, const char *uri, int flags) | |||
| if (listen_socket) { | |||
| if ((fd = ff_listen_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, | |||
| listen_timeout)) < 0) { | |||
| listen_timeout, h)) < 0) { | |||
| ret = fd; | |||
| goto fail1; | |||
| } | |||
| } else { | |||
| if ((ret = ff_listen_connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, | |||
| timeout, h)) < 0) { | |||
| timeout * 100, h)) < 0) { | |||
| if (ret == AVERROR_EXIT) | |||
| goto fail1; | |||