diff mbox

[FFmpeg-devel,1/3] avformat/network: allow to specify custom socket API

Message ID 1510219892-8142-2-git-send-email-sdk@nablet.com
State New
Headers show

Commit Message

Nablet Developer Nov. 9, 2017, 9:31 a.m. UTC
Signed-off-by: Nablet Developer <sdk@nablet.com>
---
 libavformat/network.c | 196 ++++++++++++++++++++++++++++++++------------------
 libavformat/network.h |  34 +++++++++
 2 files changed, 161 insertions(+), 69 deletions(-)
diff mbox

Patch

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);