Signed-off-by: Nablet Developer <s...@nablet.com> --- libavformat/network.c | 196 ++++++++++++++++++++++++++++++++------------------ libavformat/network.h | 34 +++++++++ 2 files changed, 161 insertions(+), 69 deletions(-)
diff --git a/libavformat/network.c b/libavformat/network.c index 6c3d9de..80d6f6e 100644 --- a/libavformat/network.c +++ b/libavformat/network.c @@ -74,24 +74,104 @@ int ff_network_init(void) return 1; } +#if HAVE_WINSOCK2_H +int ff_neterrno(void) +{ + int err = WSAGetLastError(); + switch (err) { + case WSAEWOULDBLOCK: + return AVERROR(EAGAIN); + case WSAEINTR: + return AVERROR(EINTR); + case WSAEPROTONOSUPPORT: + return AVERROR(EPROTONOSUPPORT); + case WSAETIMEDOUT: + return AVERROR(ETIMEDOUT); + case WSAECONNREFUSED: + return AVERROR(ECONNREFUSED); + case WSAEINPROGRESS: + return AVERROR(EINPROGRESS); + } + return -err; +} +#endif + +// wrap into function as ff_neterrno is define on *nix +static int ff_neterrno_wrapper(void) +{ + return ff_neterrno(); +} + +int ff_socket(int af, int type, int proto) +{ + int fd; + +#ifdef SOCK_CLOEXEC + fd = socket(af, type | SOCK_CLOEXEC, proto); + if (fd == -1 && errno == EINVAL) +#endif + { + fd = socket(af, type, proto); +#if HAVE_FCNTL + if (fd != -1) { + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + av_log(NULL, AV_LOG_DEBUG, "Failed to set close on exec\n"); + } +#endif + } +#ifdef SO_NOSIGPIPE + if (fd != -1) + setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){1}, sizeof(int)); +#endif + return fd; +} + + +const struct socket_api bsd_socket_api = { + .poll = poll, + .bind = bind, + .socket = ff_socket, + .listen = listen, + .connect = connect, + .setsockopt = setsockopt, + .getsockopt = getsockopt, + .accept = accept, + .close = closesocket, + .socket_nonblock = ff_socket_nonblock, + .neterrno = ff_neterrno_wrapper, + .send = send, + .recv = recv, + .shutdown = shutdown +}; + int ff_network_wait_fd(int fd, int write) { + return ff_network_wait_fd_ex(&bsd_socket_api, fd, write); +} + +int ff_network_wait_fd_ex(const struct socket_api * api, int fd, int write) +{ int ev = write ? POLLOUT : POLLIN; struct pollfd p = { .fd = fd, .events = ev, .revents = 0 }; int ret; - ret = poll(&p, 1, POLLING_TIME); - return ret < 0 ? ff_neterrno() : p.revents & (ev | POLLERR | POLLHUP) ? 0 : AVERROR(EAGAIN); + ret = api->poll(&p, 1, POLLING_TIME); + return ret < 0 ? api->neterrno() : p.revents & (ev | POLLERR | POLLHUP) ? 0 : AVERROR(EAGAIN); } int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb) { + return ff_network_wait_fd_timeout_ex(&bsd_socket_api, fd, write, timeout, int_cb); +} + +int ff_network_wait_fd_timeout_ex(const struct socket_api * api, int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb) +{ int ret; int64_t wait_start = 0; while (1) { if (ff_check_interrupt(int_cb)) return AVERROR_EXIT; - ret = ff_network_wait_fd(fd, write); + ret = ff_network_wait_fd_ex(api, fd, write); if (ret != AVERROR(EAGAIN)) return ret; if (timeout > 0) { @@ -110,28 +190,6 @@ void ff_network_close(void) #endif } -#if HAVE_WINSOCK2_H -int ff_neterrno(void) -{ - int err = WSAGetLastError(); - switch (err) { - case WSAEWOULDBLOCK: - return AVERROR(EAGAIN); - case WSAEINTR: - return AVERROR(EINTR); - case WSAEPROTONOSUPPORT: - return AVERROR(EPROTONOSUPPORT); - case WSAETIMEDOUT: - return AVERROR(ETIMEDOUT); - case WSAECONNREFUSED: - return AVERROR(ECONNREFUSED); - case WSAEINPROGRESS: - return AVERROR(EINPROGRESS); - } - return -err; -} -#endif - int ff_is_multicast_address(struct sockaddr *addr) { if (addr->sa_family == AF_INET) { @@ -146,7 +204,7 @@ int ff_is_multicast_address(struct sockaddr *addr) return 0; } -static int ff_poll_interrupt(struct pollfd *p, nfds_t nfds, int timeout, +static int ff_poll_interrupt_ex(const struct socket_api * api, struct pollfd *p, nfds_t nfds, int timeout, AVIOInterruptCB *cb) { int runs = timeout / POLLING_TIME; @@ -155,7 +213,7 @@ static int ff_poll_interrupt(struct pollfd *p, nfds_t nfds, int timeout, do { if (ff_check_interrupt(cb)) return AVERROR_EXIT; - ret = poll(p, nfds, POLLING_TIME); + ret = api->poll(p, nfds, POLLING_TIME); if (ret != 0) break; } while (timeout <= 0 || runs-- > 0); @@ -163,65 +221,52 @@ static int ff_poll_interrupt(struct pollfd *p, nfds_t nfds, int timeout, if (!ret) return AVERROR(ETIMEDOUT); if (ret < 0) - return ff_neterrno(); + return api->neterrno(); return ret; } -int ff_socket(int af, int type, int proto) +int ff_listen(int fd, const struct sockaddr *addr, + socklen_t addrlen) { - int fd; - -#ifdef SOCK_CLOEXEC - fd = socket(af, type | SOCK_CLOEXEC, proto); - if (fd == -1 && errno == EINVAL) -#endif - { - fd = socket(af, type, proto); -#if HAVE_FCNTL - if (fd != -1) { - if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) - av_log(NULL, AV_LOG_DEBUG, "Failed to set close on exec\n"); - } -#endif - } -#ifdef SO_NOSIGPIPE - if (fd != -1) - setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){1}, sizeof(int)); -#endif - return fd; + return ff_listen_ex(&bsd_socket_api, fd, addr, addrlen); } -int ff_listen(int fd, const struct sockaddr *addr, - socklen_t addrlen) +int ff_listen_ex(const struct socket_api * api, int fd, const struct sockaddr *addr, + socklen_t addrlen) { int ret; int reuse = 1; - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) { + if (api->setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) { av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_REUSEADDR) failed\n"); } - ret = bind(fd, addr, addrlen); + ret = api->bind(fd, addr, addrlen); if (ret) - return ff_neterrno(); + return api->neterrno(); - ret = listen(fd, 1); + ret = api->listen(fd, 1); if (ret) - return ff_neterrno(); + return api->neterrno(); return ret; } int ff_accept(int fd, int timeout, URLContext *h) { + return ff_accept_ex(&bsd_socket_api, fd, timeout, h); +} + +int ff_accept_ex(const struct socket_api * api, int fd, int timeout, URLContext *h) +{ int ret; struct pollfd lp = { fd, POLLIN, 0 }; - ret = ff_poll_interrupt(&lp, 1, timeout, &h->interrupt_callback); + ret = ff_poll_interrupt_ex(api, &lp, 1, timeout, &h->interrupt_callback); if (ret < 0) return ret; - ret = accept(fd, NULL, NULL); + ret = api->accept(fd, NULL, NULL); if (ret < 0) - return ff_neterrno(); - if (ff_socket_nonblock(ret, 1) < 0) + return api->neterrno(); + if (api->socket_nonblock(ret, 1) < 0) av_log(NULL, AV_LOG_DEBUG, "ff_socket_nonblock failed\n"); return ret; @@ -230,12 +275,18 @@ int ff_accept(int fd, int timeout, URLContext *h) int ff_listen_bind(int fd, const struct sockaddr *addr, socklen_t addrlen, int timeout, URLContext *h) { + return ff_listen_bind_ex(&bsd_socket_api, fd, addr, addrlen, timeout, h); +} + +int ff_listen_bind_ex(const struct socket_api * api, int fd, const struct sockaddr *addr, + socklen_t addrlen, int timeout, URLContext *h) +{ int ret; - if ((ret = ff_listen(fd, addr, addrlen)) < 0) + if ((ret = ff_listen_ex(api, fd, addr, addrlen)) < 0) return ret; - if ((ret = ff_accept(fd, timeout, h)) < 0) + if ((ret = ff_accept_ex(api, fd, timeout, h)) < 0) return ret; - closesocket(fd); + api->close(fd); return ret; } @@ -243,15 +294,22 @@ int ff_listen_connect(int fd, const struct sockaddr *addr, socklen_t addrlen, int timeout, URLContext *h, int will_try_next) { + return ff_listen_connect_ex(&bsd_socket_api, fd, addr, addrlen, timeout, h, will_try_next); +} + +int ff_listen_connect_ex(const struct socket_api * api, int fd, const struct sockaddr *addr, + socklen_t addrlen, int timeout, URLContext *h, + int will_try_next) +{ struct pollfd p = {fd, POLLOUT, 0}; int ret; socklen_t optlen; - if (ff_socket_nonblock(fd, 1) < 0) + if (api->socket_nonblock(fd, 1) < 0) av_log(NULL, AV_LOG_DEBUG, "ff_socket_nonblock failed\n"); - while ((ret = connect(fd, addr, addrlen))) { - ret = ff_neterrno(); + while ((ret = api->connect(fd, addr, addrlen))) { + ret = api->neterrno(); switch (ret) { case AVERROR(EINTR): if (ff_check_interrupt(&h->interrupt_callback)) @@ -259,12 +317,12 @@ int ff_listen_connect(int fd, const struct sockaddr *addr, continue; case AVERROR(EINPROGRESS): case AVERROR(EAGAIN): - ret = ff_poll_interrupt(&p, 1, timeout, &h->interrupt_callback); + ret = ff_poll_interrupt_ex(api, &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()); + if (api->getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen)) + ret = AVUNERROR(api->neterrno()); if (ret != 0) { char errbuf[100]; ret = AVERROR(ret); diff --git a/libavformat/network.h b/libavformat/network.h index f83c796..7b6cc4d 100644 --- a/libavformat/network.h +++ b/libavformat/network.h @@ -72,7 +72,27 @@ int ff_neterrno(void); #include <poll.h> #endif +struct socket_api { + int (*poll)(struct pollfd *fds, nfds_t nfds, int timeout); + int (*bind)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); + int (*socket)(int domain, int type, int protocol); + int (*listen)(int sockfd, int backlog); + int (*connect)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); + int (*getsockopt)(int sockfd, int level, int optname, void *optval, socklen_t *optlen); + int (*setsockopt)(int sockfd, int level, int optname, const void *optval, socklen_t optlen); + int (*accept)(int sockfd, struct sockaddr *addr, socklen_t *addrlen); + int (*close)(int fd); + int (*socket_nonblock)(int socket, int enable); + int (*neterrno)(void); + ssize_t (*send)(int sockfd, const void *buf, size_t len, int flags); + ssize_t (*recv)(int sockfd, void *buf, size_t len, int flags); + int (*shutdown)(int sockfd, int how); +}; + +extern const struct socket_api bsd_socket_api; + int ff_socket_nonblock(int socket, int enable); +int ff_socket_nonblock_ex(const struct socket_api * api, int socket, int enable); extern int ff_network_inited_globally; int ff_network_init(void); @@ -82,6 +102,7 @@ int ff_tls_init(void); void ff_tls_deinit(void); int ff_network_wait_fd(int fd, int write); +int ff_network_wait_fd_ex(const struct socket_api * api, int fd, int write); /** * This works similarly to ff_network_wait_fd, but waits up to 'timeout' microseconds @@ -94,6 +115,7 @@ int ff_network_wait_fd(int fd, int write); * @return 0 if data can be read/written, AVERROR(ETIMEDOUT) if timeout expired, or negative error code */ int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb); +int ff_network_wait_fd_timeout_ex(const struct socket_api * api, int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb); int ff_inet_aton (const char * str, struct in_addr * add); @@ -238,6 +260,8 @@ 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. * @@ -253,6 +277,10 @@ int ff_is_multicast_address(struct sockaddr *addr); int ff_listen_bind(int fd, const struct sockaddr *addr, socklen_t addrlen, int timeout, URLContext *h); +int ff_listen_bind_ex(const struct socket_api * api, + int fd, const struct sockaddr *addr, + socklen_t addrlen, int timeout, + URLContext *h); /** * Bind to a file descriptor to an address without accepting connections. @@ -262,6 +290,7 @@ int ff_listen_bind(int fd, const struct sockaddr *addr, * @return 0 on success or an AVERROR on failure. */ int ff_listen(int fd, const struct sockaddr *addr, socklen_t addrlen); +int ff_listen_ex(const struct socket_api * api, int fd, const struct sockaddr *addr, socklen_t addrlen); /** * Poll for a single connection on the passed file descriptor. @@ -273,6 +302,7 @@ int ff_listen(int fd, const struct sockaddr *addr, socklen_t addrlen); * or an AVERROR on failure. */ int ff_accept(int fd, int timeout, URLContext *h); +int ff_accept_ex(const struct socket_api * api, int fd, int timeout, URLContext *h); /** * Connect to a file descriptor and poll for result. @@ -292,6 +322,10 @@ int ff_accept(int fd, int timeout, URLContext *h); int ff_listen_connect(int fd, const struct sockaddr *addr, socklen_t addrlen, int timeout, URLContext *h, int will_try_next); +int ff_listen_connect_ex(const struct socket_api * api, + int fd, const struct sockaddr *addr, + socklen_t addrlen, int timeout, + URLContext *h, int will_try_next); int ff_http_match_no_proxy(const char *no_proxy, const char *hostname); -- 2.7.4 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel