Document the functions and have both use a millisecond timeout and check for interrupt.
Unified · Split
| @@ -189,8 +189,29 @@ int ff_is_multicast_address(struct sockaddr *addr) · 188 unmodified lines | |||
| 189 | return 0; | 189 | return 0; |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | static int ff_poll_interrupt(struct pollfd *p, nfds_t nfds, int timeout, | ||
| 193 | AVIOInterruptCB *cb) | ||
| 194 | { | ||
| 195 | int runs = timeout / POLLING_TIME; | ||
| 196 | int ret = 0; | ||
| 197 | |||
| 198 | do { | ||
| 199 | if (ff_check_interrupt(cb)) | ||
| 200 | return AVERROR_EXIT; | ||
| 201 | ret = poll(p, nfds, POLLING_TIME); | ||
| 202 | if (ret != 0) | ||
| 203 | break; | ||
| 204 | } while (timeout < 0 || runs-- > 0); | ||
| 205 | |||
| 206 | if (!ret) | ||
| 207 | return AVERROR(ETIMEDOUT); | ||
| 208 | if (ret < 0) | ||
| 209 | return AVERROR(errno); | ||
| 210 | return ret; | ||
| 211 | } | ||
| 212 | |||
| 192 | int ff_listen_bind(int fd, const struct sockaddr *addr, | 213 | int ff_listen_bind(int fd, const struct sockaddr *addr, |
| 193 | socklen_t addrlen, int timeout) | 214 | socklen_t addrlen, int timeout, URLContext *h) |
| 194 | { | 215 | { |
| 195 | int ret; | 216 | int ret; |
| 196 | int reuse = 1; | 217 | int reuse = 1; |
| @@ -204,9 +225,9 @@ int ff_listen_bind(int fd, const struct sockaddr *addr, · 7 unmodified lines | |||
| 204 | if (ret) | 225 | if (ret) |
| 205 | return ff_neterrno(); | 226 | return ff_neterrno(); |
| 206 | 227 | ||
| 207 | ret = poll(&lp, 1, timeout >= 0 ? timeout : -1); | 228 | ret = ff_poll_interrupt(&lp, 1, timeout, &h->interrupt_callback); |
| 208 | if (ret <= 0) | 229 | if (ret < 0) |
| 209 | return AVERROR(ETIMEDOUT); | 230 | return ret; |
| 210 | 231 | ||
| 211 | ret = accept(fd, NULL, NULL); | 232 | ret = accept(fd, NULL, NULL); |
| 212 | if (ret < 0) | 233 | if (ret < 0) |
| @@ -236,15 +257,9 @@ int ff_listen_connect(int fd, const struct sockaddr *addr, · 23 unmodified lines | |||
| 236 | continue; | 257 | continue; |
| 237 | case AVERROR(EINPROGRESS): | 258 | case AVERROR(EINPROGRESS): |
| 238 | case AVERROR(EAGAIN): | 259 | case AVERROR(EAGAIN): |
| 239 | while (timeout--) { | 260 | ret = ff_poll_interrupt(&p, 1, timeout, &h->interrupt_callback); |
| 240 | if (ff_check_interrupt(&h->interrupt_callback)) | 261 | if (ret < 0) |
| 241 | return AVERROR_EXIT; | 262 | return ret; |
| 242 | ret = poll(&p, 1, 100); | ||
| 243 | if (ret > 0) | ||
| 244 | break; | ||
| 245 | } | ||
| 246 | if (ret <= 0) | ||
| 247 | return AVERROR(ETIMEDOUT); | ||
| 248 | optlen = sizeof(ret); | 263 | optlen = sizeof(ret); |
| 249 | if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen)) | 264 | if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen)) |
| 250 | ret = AVUNERROR(ff_neterrno()); | 265 | ret = AVUNERROR(ff_neterrno()); |
| @@ -210,9 +210,38 @@ const char *ff_gai_strerror(int ecode); · 209 unmodified lines | |||
| 210 | 210 | ||
| 211 | int ff_is_multicast_address(struct sockaddr *addr); | 211 | int ff_is_multicast_address(struct sockaddr *addr); |
| 212 | 212 | ||
| 213 | #define POLLING_TIME 100 /// Time in milliseconds between interrupt check | ||
| 214 | |||
| 215 | /** | ||
| 216 | * Bind to a file descriptor and poll for a connection. | ||
| 217 | * | ||
| 218 | * @param fd First argument of bind(). | ||
| 219 | * @param addr Second argument of bind(). | ||
| 220 | * @param addrlen Third argument of bind(). | ||
| 221 | * @param timeout Polling timeout in milliseconds. | ||
| 222 | * @param h URLContext providing interrupt check | ||
| 223 | * callback and logging context. | ||
| 224 | * @return A non-blocking file descriptor on success | ||
| 225 | * or an AVERROR on failure. | ||
| 226 | */ | ||
| 213 | int ff_listen_bind(int fd, const struct sockaddr *addr, | 227 | int ff_listen_bind(int fd, const struct sockaddr *addr, |
| 214 | socklen_t addrlen, int timeout); | 228 | socklen_t addrlen, int timeout, |
| 229 | URLContext *h); | ||
| 230 | |||
| 231 | /** | ||
| 232 | * Connect to a file descriptor and poll for result. | ||
| 233 | * | ||
| 234 | * @param fd First argument of connect(), | ||
| 235 | * will be set as non-blocking. | ||
| 236 | * @param addr Second argument of connect(). | ||
| 237 | * @param addrlen Third argument of connect(). | ||
| 238 | * @param timeout Polling timeout in milliseconds. | ||
| 239 | * @param h URLContext providing interrupt check | ||
| 240 | * callback and logging context. | ||
| 241 | * @return 0 on success, AVERROR on failure. | ||
| 242 | */ | ||
| 215 | int ff_listen_connect(int fd, const struct sockaddr *addr, | 243 | int ff_listen_connect(int fd, const struct sockaddr *addr, |
| 216 | socklen_t addrlen, int timeout, | 244 | socklen_t addrlen, int timeout, |
| 217 | URLContext *h); | 245 | URLContext *h); |
| 246 | |||
| 218 | #endif /* AVFORMAT_NETWORK_H */ | 247 | #endif /* AVFORMAT_NETWORK_H */ |
| @@ -92,13 +92,13 @@ static int tcp_open(URLContext *h, const char *uri, int flags) · 91 unmodified lines | |||
| 92 | 92 | ||
| 93 | if (listen_socket) { | 93 | if (listen_socket) { |
| 94 | if ((fd = ff_listen_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, | 94 | if ((fd = ff_listen_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, |
| 95 | listen_timeout)) < 0) { | 95 | listen_timeout, h)) < 0) { |
| 96 | ret = fd; | 96 | ret = fd; |
| 97 | goto fail1; | 97 | goto fail1; |
| 98 | } | 98 | } |
| 99 | } else { | 99 | } else { |
| 100 | if ((ret = ff_listen_connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, | 100 | if ((ret = ff_listen_connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, |
| 101 | timeout, h)) < 0) { | 101 | timeout * 100, h)) < 0) { |
| 102 | 102 | ||
| 103 | if (ret == AVERROR_EXIT) | 103 | if (ret == AVERROR_EXIT) |
| 104 | goto fail1; | 104 | goto fail1; |