* qatar/master: network: factor out connect-listening code Conflicts: libavformat/network.h libavformat/tcp.c Merged-by: Michael Niedermayer <michaelni@gmx.at>tags/n2.0
| @@ -20,6 +20,7 @@ | |||||
| #include "libavutil/avutil.h" | #include "libavutil/avutil.h" | ||||
| #include "network.h" | #include "network.h" | ||||
| #include "url.h" | |||||
| #include "libavcodec/internal.h" | #include "libavcodec/internal.h" | ||||
| #include "libavutil/mem.h" | #include "libavutil/mem.h" | ||||
| #include "url.h" | #include "url.h" | ||||
| @@ -241,3 +242,50 @@ int ff_listen_bind(int fd, const struct sockaddr *addr, | |||||
| ff_socket_nonblock(ret, 1); | ff_socket_nonblock(ret, 1); | ||||
| return ret; | return ret; | ||||
| } | } | ||||
| int ff_listen_connect(int fd, const struct sockaddr *addr, | |||||
| socklen_t addrlen, int rw_timeout, URLContext *h) | |||||
| { | |||||
| struct pollfd p = {fd, POLLOUT, 0}; | |||||
| int64_t wait_started; | |||||
| int ret; | |||||
| socklen_t optlen; | |||||
| ff_socket_nonblock(fd, 1); | |||||
| while ((ret = connect(fd, addr, addrlen))) { | |||||
| ret = ff_neterrno(); | |||||
| switch (ret) { | |||||
| case AVERROR(EINTR): | |||||
| if (ff_check_interrupt(&h->interrupt_callback)) | |||||
| return AVERROR_EXIT; | |||||
| continue; | |||||
| case AVERROR(EINPROGRESS): | |||||
| case AVERROR(EAGAIN): | |||||
| wait_started = av_gettime(); | |||||
| do { | |||||
| if (ff_check_interrupt(&h->interrupt_callback)) | |||||
| return AVERROR_EXIT; | |||||
| ret = poll(&p, 1, 100); | |||||
| if (ret > 0) | |||||
| break; | |||||
| } while (!rw_timeout || (av_gettime() - wait_started < rw_timeout)); | |||||
| if (ret <= 0) | |||||
| return AVERROR(ETIMEDOUT); | |||||
| optlen = sizeof(ret); | |||||
| if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen)) | |||||
| ret = AVUNERROR(ff_neterrno()); | |||||
| if (ret != 0) { | |||||
| char errbuf[100]; | |||||
| ret = AVERROR(ret); | |||||
| av_strerror(ret, errbuf, sizeof(errbuf)); | |||||
| av_log(h, AV_LOG_ERROR, | |||||
| "Connection to %s failed: %s\n", | |||||
| h->filename, errbuf); | |||||
| } | |||||
| default: | |||||
| return ret; | |||||
| } | |||||
| } | |||||
| return ret; | |||||
| } | |||||
| @@ -28,6 +28,7 @@ | |||||
| #include "libavutil/error.h" | #include "libavutil/error.h" | ||||
| #include "os_support.h" | #include "os_support.h" | ||||
| #include "avio.h" | #include "avio.h" | ||||
| #include "url.h" | |||||
| #if HAVE_UNISTD_H | #if HAVE_UNISTD_H | ||||
| #include <unistd.h> | #include <unistd.h> | ||||
| @@ -224,5 +225,7 @@ int ff_is_multicast_address(struct sockaddr *addr); | |||||
| int ff_listen_bind(int fd, const struct sockaddr *addr, | int ff_listen_bind(int fd, const struct sockaddr *addr, | ||||
| socklen_t addrlen, int timeout); | socklen_t addrlen, int timeout); | ||||
| int ff_listen_connect(int fd, const struct sockaddr *addr, | |||||
| socklen_t addrlen, int timeout, | |||||
| URLContext *h); | |||||
| #endif /* AVFORMAT_NETWORK_H */ | #endif /* AVFORMAT_NETWORK_H */ | ||||
| @@ -64,7 +64,6 @@ static int tcp_open(URLContext *h, const char *uri, int flags) | |||||
| const char *p; | const char *p; | ||||
| char buf[256]; | char buf[256]; | ||||
| int ret; | int ret; | ||||
| socklen_t optlen; | |||||
| char hostname[1024],proto[1024],path[1024]; | char hostname[1024],proto[1024],path[1024]; | ||||
| char portstr[10]; | char portstr[10]; | ||||
| h->rw_timeout = 5000000; | h->rw_timeout = 5000000; | ||||
| @@ -121,55 +120,16 @@ static int tcp_open(URLContext *h, const char *uri, int flags) | |||||
| goto fail1; | goto fail1; | ||||
| } | } | ||||
| } else { | } else { | ||||
| redo: | |||||
| ff_socket_nonblock(fd, 1); | |||||
| ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); | |||||
| } | |||||
| if ((ret = ff_listen_connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, | |||||
| h->rw_timeout, h)) < 0) { | |||||
| if (ret < 0) { | |||||
| struct pollfd p = {fd, POLLOUT, 0}; | |||||
| int64_t wait_started; | |||||
| ret = ff_neterrno(); | |||||
| if (ret == AVERROR(EINTR)) { | |||||
| if (ff_check_interrupt(&h->interrupt_callback)) { | |||||
| ret = AVERROR_EXIT; | |||||
| if (ret == AVERROR_EXIT) | |||||
| goto fail1; | goto fail1; | ||||
| } | |||||
| goto redo; | |||||
| } | |||||
| if (ret != AVERROR(EINPROGRESS) && | |||||
| ret != AVERROR(EAGAIN)) | |||||
| goto fail; | |||||
| /* wait until we are connected or until abort */ | |||||
| wait_started = av_gettime(); | |||||
| do { | |||||
| if (ff_check_interrupt(&h->interrupt_callback)) { | |||||
| ret = AVERROR_EXIT; | |||||
| goto fail1; | |||||
| } | |||||
| ret = poll(&p, 1, 100); | |||||
| if (ret > 0) | |||||
| break; | |||||
| } while (!h->rw_timeout || (av_gettime() - wait_started < h->rw_timeout)); | |||||
| if (ret <= 0) { | |||||
| ret = AVERROR(ETIMEDOUT); | |||||
| goto fail; | |||||
| } | |||||
| /* test error */ | |||||
| optlen = sizeof(ret); | |||||
| if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen)) | |||||
| ret = AVUNERROR(ff_neterrno()); | |||||
| if (ret != 0) { | |||||
| char errbuf[100]; | |||||
| ret = AVERROR(ret); | |||||
| av_strerror(ret, errbuf, sizeof(errbuf)); | |||||
| av_log(h, AV_LOG_ERROR, | |||||
| "TCP connection to %s:%d failed: %s\n", | |||||
| hostname, port, errbuf); | |||||
| goto fail; | |||||
| else | |||||
| goto fail; | |||||
| } | } | ||||
| } | } | ||||
| h->is_streamed = 1; | h->is_streamed = 1; | ||||
| s->fd = fd; | s->fd = fd; | ||||
| freeaddrinfo(ai); | freeaddrinfo(ai); | ||||