[FFmpeg-devel] [PATCH 1/3] avformat/network: allow to specify custom socket API
Nablet Developer
sdk at nablet.com
Thu Nov 9 11:31:30 EET 2017
Signed-off-by: Nablet Developer <sdk at 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
More information about the ffmpeg-devel
mailing list