From patchwork Thu Nov 9 09:31:30 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nablet Developer X-Patchwork-Id: 5985 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.161.90 with SMTP id m26csp1809594jah; Thu, 9 Nov 2017 01:32:36 -0800 (PST) X-Google-Smtp-Source: ABhQp+SHhCxev3lfZTKmLTuBSfM+hpb9ddGNSzQgX65A/aE44dW0IpbhOPFQJbQjxUZslXkKvMMv X-Received: by 10.223.189.13 with SMTP id j13mr2952797wrh.94.1510219956327; Thu, 09 Nov 2017 01:32:36 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1510219956; cv=none; d=google.com; s=arc-20160816; b=w+zWZnHtGuBynXlnpD8xuj1rBWPrgFwyj7XTYjCLBbsxbtQg9yw5NL7IV/GoRRTQ5I bq+2KB0u/q9M27wDtJX5sHfJnGQk+jsQ2fd+D9Hy522iNxo1TsgsapMLvk1TP4wKCxkf q7nMKMuXK8PT+Ngv6T+rXhLAou84vDsD5SSV3J2ZqbKmjCcXjbzSbGKJt0aUQG14YXJr 318WUZDi/ULzI7971LsBI8IvNhjRCcLmmXDI2/8XVQP+sTNT6CMZ3TSMwX4dL7dUUYZB Kws3iM5UOJmGMOKiZ7COSSSuG6/pCwatBZ/uposAoqio80a5a5xhG9ljFtclq4eWO7S9 zEHQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:delivered-to:arc-authentication-results; bh=5kPphpReTMWjenFKaCBcBs42JiE+AQUZDXjNhANzLho=; b=loKWZv0cltsd1PMurMhhxxNl9r5nmtfU+eXuBfkfa+qdu7z2CZL4g92Vg9lPoY5UEq 6ip1wUZVra1XtKtsl3wZOIhuxRI3yCrYnWhJU1dVTDXvcCfuoq8HONQL/i4IEhbJgkz0 7qij4McDCpHA246JfCX06gUndA08s7+hxiDYPlIdz4TBXsj4MzoR5NHeMX15WXGr3Lnr efiwsfzpb+O56jqYgj3xf3iD3iKVC7cDSVJKmXi9Qoa2nEnlN/puGcRBRgT05a0lEpXe pHfo1kOQUIa3WODCx892vpwyeMJPr3J6Ef4MQrlIJ5T45zXQRAVimnQuct1ndylx+fuE DHSA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id j198si4935556wmj.105.2017.11.09.01.32.35; Thu, 09 Nov 2017 01:32:36 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 12C98689E30; Thu, 9 Nov 2017 11:32:16 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mout.kundenserver.de (mout.kundenserver.de [212.227.17.13]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 50041689E03 for ; Thu, 9 Nov 2017 11:32:10 +0200 (EET) Received: from ubuntu-server.internal.divx.com ([91.216.211.197]) by mrelayeu.kundenserver.de (mreue103 [212.227.15.183]) with ESMTPSA (Nemesis) id 0Lyk6B-1fGe3729ah-0168Bf; Thu, 09 Nov 2017 10:32:22 +0100 From: Nablet Developer To: ffmpeg-devel@ffmpeg.org Date: Thu, 9 Nov 2017 16:31:30 +0700 Message-Id: <1510219892-8142-2-git-send-email-sdk@nablet.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1510219892-8142-1-git-send-email-sdk@nablet.com> References: <1510219892-8142-1-git-send-email-sdk@nablet.com> X-Provags-ID: V03:K0:z29gYfPm/GJFh1odGy68+DKD95sUXJ/R0f3/SgTbbC3akZh7iMu YSCppDxxjyHohdg+FPTloGKkVtV6ttZTeuHG02z0wUnFgITPk1fFoz1kcKFxKJWegpdk/2Y BK/Fi5fpI/QhhXy/sOqiozC53pKPSm93pPAB8aRO99XCtCXaomNIbLROSlWjYopisIx2OhH ltsdivUtz4ZonEptZdS7Q== X-UI-Out-Filterresults: notjunk:1; V01:K0:mOQY1ipw8Ww=:rqpJO0S5KN9IX5sVkCwg4q ygQCCYVSYDgcOMXGKYf1N2aR2TFjEet7JFOBtOeQA46ni9wSHVHe3Fzrf05bGZhccTC7SRDRB vvQVenhd8GiH5Gxd3sxYVW+AcnER+XKnG2rLtcD8sgJtnTjGyHHAodHQDNYVxZeHER0Q0Ucz9 IOlG6aa8tuP+r9mp7XPkt3Iy5RC+eYZhmjFoJZakH/S3cBJa0zF54Rn4suKpZiiCSxnnKtJ2w Oi2A0csZyygMEEfJNJhVD4OX+rrwiEq0n0R7mrog9dnh2uOtBOugOx3ggFGPUJroERfhlg/5M ZiwlsyPcq7ElFGFZFtLvhu0+kCbin51IJUH1b1vNTA2LujYdzTGnN2B6ULZ3WJp02jipj7XEB bkufBpxGF28TGsEtVE02ksN9REMV+GRnyXT3rfSejCqGxXAZBTlbfbd6+elGIDC/8T45mTeon RZyXsRBFsu9T229IKiVSEPSs64p3AtijOZak7GJiOowXv6wM9iajtMP4t54VJfMs6JNfyNYRz M4vOlkW3hYMQj+YN6pNsddqDO7v0IUiadpx8RgJcBAmbBKGVcrAxSI2WlPMLwEp0zhXcyxLIP J6SqJwQNufxzsF0N8aQKDozlnYChdhansfU7wdDBjHOx+OlIwCb+wzbLRqT6PuzI09CyP36x9 DNLAH1/iWmoVYfnOAakEWwOklNA5eOegu2Mrk/c10yGEyGiicw4nbiDQQ0ZliPlll64w0U2gt b9bmN7X6X6d6d8ILzsAIOqJYQFL2tnECR2GsAw== Subject: [FFmpeg-devel] [PATCH 1/3] avformat/network: allow to specify custom socket API X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Nablet Developer MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Nablet Developer --- 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 #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);