[vlc-commits] tcp: gather socket accept/listen helpers
Rémi Denis-Courmont
git at videolan.org
Sun Nov 11 16:33:27 CET 2018
vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Fri Nov 9 22:49:12 2018 +0200| [14827d5587753a3e91cbd50d50ce8fa39fe0a190] | committer: Rémi Denis-Courmont
tcp: gather socket accept/listen helpers
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=14827d5587753a3e91cbd50d50ce8fa39fe0a190
---
src/network/io.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/network/tcp.c | 199 ------------------------------------------------------
2 files changed, 185 insertions(+), 199 deletions(-)
diff --git a/src/network/io.c b/src/network/io.c
index 5aa5d65c65..a35e0767a9 100644
--- a/src/network/io.c
+++ b/src/network/io.c
@@ -39,6 +39,9 @@
#include <assert.h>
#include <unistd.h>
+#ifdef HAVE_POLL
+# include <poll.h>
+#endif
#ifdef HAVE_LINUX_DCCP_H
/* TODO: use glibc instead of linux-kernel headers */
# include <linux/dccp.h>
@@ -48,6 +51,14 @@
#include <vlc_common.h>
#include <vlc_network.h>
#include <vlc_interrupt.h>
+#if defined (_WIN32)
+# undef EINPROGRESS
+# define EINPROGRESS WSAEWOULDBLOCK
+# undef EWOULDBLOCK
+# define EWOULDBLOCK WSAEWOULDBLOCK
+# undef EAGAIN
+# define EAGAIN WSAEWOULDBLOCK
+#endif
extern int rootwrap_bind (int family, int socktype, int protocol,
const struct sockaddr *addr, size_t alen);
@@ -102,6 +113,100 @@ int net_Socket (vlc_object_t *p_this, int family, int socktype,
return fd;
}
+int (net_Connect)(vlc_object_t *obj, const char *host, int serv,
+ int type, int proto)
+{
+ struct addrinfo hints = {
+ .ai_socktype = type,
+ .ai_protocol = proto,
+ .ai_flags = AI_NUMERICSERV | AI_IDN,
+ }, *res;
+ int ret = -1;
+
+ int val = vlc_getaddrinfo_i11e(host, serv, &hints, &res);
+ if (val)
+ {
+ msg_Err(obj, "cannot resolve %s port %d : %s", host, serv,
+ gai_strerror (val));
+ return -1;
+ }
+
+ vlc_tick_t timeout = VLC_TICK_FROM_MS(var_InheritInteger(obj,
+ "ipv4-timeout"));
+
+ for (struct addrinfo *ptr = res; ptr != NULL; ptr = ptr->ai_next)
+ {
+ int fd = net_Socket(obj, ptr->ai_family,
+ ptr->ai_socktype, ptr->ai_protocol);
+ if (fd == -1)
+ {
+ msg_Dbg(obj, "socket error: %s", vlc_strerror_c(net_errno));
+ continue;
+ }
+
+ if (connect(fd, ptr->ai_addr, ptr->ai_addrlen))
+ {
+ if (net_errno != EINPROGRESS && errno != EINTR)
+ {
+ msg_Err(obj, "connection failed: %s",
+ vlc_strerror_c(net_errno));
+ goto next_ai;
+ }
+
+ struct pollfd ufd;
+ vlc_tick_t deadline = VLC_TICK_INVALID;
+
+ ufd.fd = fd;
+ ufd.events = POLLOUT;
+ deadline = vlc_tick_now() + timeout;
+
+ do
+ {
+ vlc_tick_t now = vlc_tick_now();
+
+ if (vlc_killed())
+ goto next_ai;
+
+ if (now > deadline)
+ now = deadline;
+
+ val = vlc_poll_i11e(&ufd, 1, MS_FROM_VLC_TICK(deadline - now));
+ }
+ while (val == -1 && errno == EINTR);
+
+ switch (val)
+ {
+ case -1: /* error */
+ msg_Err(obj, "polling error: %s",
+ vlc_strerror_c(net_errno));
+ goto next_ai;
+
+ case 0: /* timeout */
+ msg_Warn(obj, "connection timed out");
+ goto next_ai;
+ }
+
+ /* There is NO WAY around checking SO_ERROR.
+ * Don't ifdef it out!!! */
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &val,
+ &(socklen_t){ sizeof (val) }) || val)
+ {
+ msg_Err(obj, "connection failed: %s", vlc_strerror_c(val));
+ goto next_ai;
+ }
+ }
+
+ msg_Dbg(obj, "connection succeeded (socket = %d)", fd);
+ ret = fd; /* success! */
+ break;
+
+next_ai: /* failure */
+ net_Close(fd);
+ }
+
+ freeaddrinfo(res);
+ return ret;
+}
int *net_Listen (vlc_object_t *p_this, const char *psz_host,
unsigned i_port, int type, int protocol)
@@ -224,6 +329,86 @@ int *net_Listen (vlc_object_t *p_this, const char *psz_host,
return sockv;
}
+void net_ListenClose(int *fds)
+{
+ if (fds != NULL)
+ {
+ for (int *p = fds; *p != -1; p++)
+ net_Close(*p);
+
+ free(fds);
+ }
+}
+
+int net_AcceptSingle(vlc_object_t *obj, int lfd)
+{
+ int fd = vlc_accept(lfd, NULL, NULL, true);
+ if (fd == -1)
+ {
+ if (net_errno != EAGAIN)
+#if (EAGAIN != EWOULDBLOCK)
+ if (net_errno != EWOULDBLOCK)
+#endif
+ msg_Err(obj, "accept failed (from socket %d): %s", lfd,
+ vlc_strerror_c(net_errno));
+ return -1;
+ }
+
+ msg_Dbg(obj, "accepted socket %d (from socket %d)", fd, lfd);
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int));
+ return fd;
+}
+
+#undef net_Accept
+int net_Accept(vlc_object_t *obj, int *fds)
+{
+ assert(fds != NULL);
+
+ unsigned n = 0;
+ while (fds[n] != -1)
+ n++;
+
+ struct pollfd ufd[n];
+ /* Initialize file descriptor set */
+ for (unsigned i = 0; i < n; i++)
+ {
+ ufd[i].fd = fds[i];
+ ufd[i].events = POLLIN;
+ }
+
+ for (;;)
+ {
+ while (poll(ufd, n, -1) == -1)
+ {
+ if (net_errno != EINTR)
+ {
+ msg_Err(obj, "poll error: %s", vlc_strerror_c(net_errno));
+ return -1;
+ }
+ }
+
+ for (unsigned i = 0; i < n; i++)
+ {
+ if (ufd[i].revents == 0)
+ continue;
+
+ int sfd = ufd[i].fd;
+ int fd = net_AcceptSingle(obj, sfd);
+ if (fd == -1)
+ continue;
+
+ /*
+ * Move listening socket to the end to let the others in the
+ * set a chance next time.
+ */
+ memmove(fds + i, fds + i + 1, n - (i + 1));
+ fds[n - 1] = sfd;
+ return fd;
+ }
+ }
+ return -1;
+}
+
ssize_t (net_Read)(vlc_object_t *restrict obj, int fd,
void *restrict buf, size_t len)
{
diff --git a/src/network/tcp.c b/src/network/tcp.c
index fab3032249..eb398c9336 100644
--- a/src/network/tcp.c
+++ b/src/network/tcp.c
@@ -32,199 +32,12 @@
#include <vlc_common.h>
-#include <errno.h>
-#include <assert.h>
-#include <limits.h>
#include <unistd.h>
-#ifdef HAVE_POLL
-# include <poll.h>
-#endif
#include <vlc_network.h>
-#if defined (_WIN32)
-# undef EINPROGRESS
-# define EINPROGRESS WSAEWOULDBLOCK
-# undef EWOULDBLOCK
-# define EWOULDBLOCK WSAEWOULDBLOCK
-# undef EAGAIN
-# define EAGAIN WSAEWOULDBLOCK
-#endif
#include <vlc_interrupt.h>
/*****************************************************************************
- * net_Connect:
- *****************************************************************************
- * Open a network connection.
- * @return socket handler or -1 on error.
- *****************************************************************************/
-int (net_Connect)(vlc_object_t *obj, const char *host, int serv,
- int type, int proto)
-{
- struct addrinfo hints = {
- .ai_socktype = type,
- .ai_protocol = proto,
- .ai_flags = AI_NUMERICSERV | AI_IDN,
- }, *res;
- int ret = -1;
-
- int val = vlc_getaddrinfo_i11e(host, serv, &hints, &res);
- if (val)
- {
- msg_Err(obj, "cannot resolve %s port %d : %s", host, serv,
- gai_strerror (val));
- return -1;
- }
-
- vlc_tick_t timeout = VLC_TICK_FROM_MS(var_InheritInteger(obj,
- "ipv4-timeout"));
-
- for (struct addrinfo *ptr = res; ptr != NULL; ptr = ptr->ai_next)
- {
- int fd = net_Socket(obj, ptr->ai_family,
- ptr->ai_socktype, ptr->ai_protocol);
- if (fd == -1)
- {
- msg_Dbg(obj, "socket error: %s", vlc_strerror_c(net_errno));
- continue;
- }
-
- if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) )
- {
- if( net_errno != EINPROGRESS && errno != EINTR )
- {
- msg_Err(obj, "connection failed: %s",
- vlc_strerror_c(net_errno));
- goto next_ai;
- }
-
- struct pollfd ufd;
- vlc_tick_t deadline = VLC_TICK_INVALID;
-
- ufd.fd = fd;
- ufd.events = POLLOUT;
- deadline = vlc_tick_now() + timeout;
-
- do
- {
- vlc_tick_t now = vlc_tick_now();
-
- if (vlc_killed())
- goto next_ai;
-
- if (now > deadline)
- now = deadline;
-
- val = vlc_poll_i11e(&ufd, 1, MS_FROM_VLC_TICK(deadline - now));
- }
- while (val == -1 && errno == EINTR);
-
- switch (val)
- {
- case -1: /* error */
- msg_Err(obj, "polling error: %s",
- vlc_strerror_c(net_errno));
- goto next_ai;
-
- case 0: /* timeout */
- msg_Warn(obj, "connection timed out");
- goto next_ai;
- }
-
- /* There is NO WAY around checking SO_ERROR.
- * Don't ifdef it out!!! */
- if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &val,
- &(socklen_t){ sizeof (val) }) || val)
- {
- msg_Err(obj, "connection failed: %s", vlc_strerror_c(val));
- goto next_ai;
- }
- }
-
- msg_Dbg(obj, "connection succeeded (socket = %d)", fd);
- ret = fd; /* success! */
- break;
-
-next_ai: /* failure */
- net_Close( fd );
- }
-
- freeaddrinfo( res );
- return ret;
-}
-
-
-int net_AcceptSingle (vlc_object_t *obj, int lfd)
-{
- int fd = vlc_accept (lfd, NULL, NULL, true);
- if (fd == -1)
- {
- if (net_errno != EAGAIN)
-#if (EAGAIN != EWOULDBLOCK)
- if (net_errno != EWOULDBLOCK)
-#endif
- msg_Err (obj, "accept failed (from socket %d): %s", lfd,
- vlc_strerror_c(net_errno));
- return -1;
- }
-
- msg_Dbg (obj, "accepted socket %d (from socket %d)", fd, lfd);
- setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int));
- return fd;
-}
-
-
-#undef net_Accept
-int net_Accept (vlc_object_t *p_this, int *pi_fd)
-{
- assert (pi_fd != NULL);
-
- unsigned n = 0;
- while (pi_fd[n] != -1)
- n++;
-
- struct pollfd ufd[n];
- /* Initialize file descriptor set */
- for (unsigned i = 0; i < n; i++)
- {
- ufd[i].fd = pi_fd[i];
- ufd[i].events = POLLIN;
- }
-
- for (;;)
- {
- while (poll (ufd, n, -1) == -1)
- {
- if (net_errno != EINTR)
- {
- msg_Err (p_this, "poll error: %s", vlc_strerror_c(net_errno));
- return -1;
- }
- }
-
- for (unsigned i = 0; i < n; i++)
- {
- if (ufd[i].revents == 0)
- continue;
-
- int sfd = ufd[i].fd;
- int fd = net_AcceptSingle (p_this, sfd);
- if (fd == -1)
- continue;
-
- /*
- * Move listening socket to the end to let the others in the
- * set a chance next time.
- */
- memmove (pi_fd + i, pi_fd + i + 1, n - (i + 1));
- pi_fd[n - 1] = sfd;
- return fd;
- }
- }
- return -1;
-}
-
-
-/*****************************************************************************
* SocksNegotiate:
*****************************************************************************
* Negotiate authentication with a SOCKS server.
@@ -482,15 +295,3 @@ int (net_ConnectTCP)(vlc_object_t *obj, const char *host, int serv)
return fd;
}
-
-void net_ListenClose( int *pi_fd )
-{
- if( pi_fd != NULL )
- {
- int *pi;
-
- for( pi = pi_fd; *pi != -1; pi++ )
- net_Close( *pi );
- free( pi_fd );
- }
-}
More information about the vlc-commits
mailing list